Beispiel #1
0
/* use tree tn, match var, by mode, output in avp params */
static int mt_match(struct sip_msg *msg, gparam_t *tn, gparam_t *var,
		gparam_t *mode)
{
	str tname;
	str tomatch;
	int mval;
	m_tree_t *tr = NULL;
	
	if(msg==NULL)
	{
		LM_ERR("received null msg\n");
		return -1;
	}

	if(fixup_get_svalue(msg, tn, &tname)<0)
	{
		LM_ERR("cannot get the tree name\n");
		return -1;
	}
	if(fixup_get_svalue(msg, var, &tomatch)<0)
	{
		LM_ERR("cannot get the match var\n");
		return -1;
	}
	if(fixup_get_ivalue(msg, mode, &mval)<0)
	{
		LM_ERR("cannot get the mode\n");
		return -1;
	}
	
again:
	lock_get( mt_lock );
	if (mt_reload_flag) {
		lock_release( mt_lock );
		sleep_us(5);
		goto again;
	}
	mt_tree_refcnt++;
	lock_release( mt_lock );

	tr = mt_get_tree(&tname);
	if(tr==NULL)
	{
		/* no tree with such name*/
		goto error;
	}

	if(mt_match_prefix(msg, tr, &tomatch, mval)<0)
	{
		LM_INFO("no prefix found in [%.*s] for [%.*s]\n",
				tname.len, tname.s,
				tomatch.len, tomatch.s);
		goto error;
	}
	
	lock_get( mt_lock );
	mt_tree_refcnt--;
	lock_release( mt_lock );
	return 1;

error:
	lock_get( mt_lock );
	mt_tree_refcnt--;
	lock_release( mt_lock );
	return -1;
}
Beispiel #2
0
static int db_restore(void)
{
	ua_pres_t* p= NULL;
	db_key_t result_cols[20];
	db_res_t *res= NULL;
	db_row_t *row = NULL;
	db_val_t *row_vals= NULL;
	str pres_uri, pres_id, to_uri;
	str etag, tuple_id;
	str watcher_uri, call_id;
	str to_tag, from_tag, remote_contact;
	str record_route, contact, extra_headers;
	int size= 0, i;
	int n_result_cols= 0;
	int puri_col,touri_col,pid_col,expires_col,flag_col,etag_col, desired_expires_col;
	int watcher_col,callid_col,totag_col,fromtag_col,cseq_col,remote_contact_col;
	int event_col,contact_col,tuple_col,record_route_col, extra_headers_col;
	int version_col;
	int no_rows = 10;

	result_cols[puri_col=n_result_cols++]	= &str_pres_uri_col;
	result_cols[touri_col=n_result_cols++]	= &str_to_uri_col;
	result_cols[pid_col=n_result_cols++]	= &str_pres_id_col;
	result_cols[expires_col=n_result_cols++]= &str_expires_col;
	result_cols[flag_col=n_result_cols++]	= &str_flag_col;
	result_cols[etag_col=n_result_cols++]	= &str_etag_col;
	result_cols[tuple_col=n_result_cols++]	= &str_tuple_id_col;
	result_cols[watcher_col=n_result_cols++]= &str_watcher_uri_col;
	result_cols[callid_col=n_result_cols++] = &str_call_id_col;
	result_cols[totag_col=n_result_cols++]	= &str_to_tag_col;
	result_cols[fromtag_col=n_result_cols++]= &str_from_tag_col;
	result_cols[cseq_col= n_result_cols++]	= &str_cseq_col;
	result_cols[event_col= n_result_cols++]	= &str_event_col;
	result_cols[record_route_col= n_result_cols++]	= &str_record_route_col;
	result_cols[contact_col= n_result_cols++]	= &str_contact_col;
	result_cols[remote_contact_col= n_result_cols++]	= &str_remote_contact_col;
	result_cols[extra_headers_col= n_result_cols++]	= &str_extra_headers_col;
	result_cols[desired_expires_col= n_result_cols++]	= &str_desired_expires_col;
	result_cols[version_col= n_result_cols++]	= &str_version_col;

	if(!pua_db)
	{
		LM_ERR("null database connection\n");
		return -1;
	}

	if(pua_dbf.use_table(pua_db, &db_table)< 0)
	{
		LM_ERR("in use table\n");
		return -1;
	}

	if (DB_CAPABILITY(pua_dbf, DB_CAP_FETCH)) {
		if(pua_dbf.query(pua_db,0, 0, 0, result_cols,0, n_result_cols, 0,0)< 0)
		{
			LM_ERR("while querying table\n");
			return -1;
		}
		no_rows = estimate_available_rows( 128+128+8+8+4+32+64+64+128+
			128+64+64+16+64, n_result_cols);
		if (no_rows==0) no_rows = 10;

		if(pua_dbf.fetch_result(pua_db, &res, no_rows)<0)
		{
			LM_ERR("Error fetching rows\n");
			return -1;
		}
	} else {
		if(pua_dbf.query(pua_db,0, 0, 0,result_cols,0,n_result_cols,0,&res)< 0)
		{
			LM_ERR("while querrying table\n");
			if(res)
			{
				pua_dbf.free_result(pua_db, res);
				res = NULL;
			}
			return -1;
		}
	}

	if(res== NULL)
		return -1;

	if(res->n<=0)
	{
		LM_INFO("the query returned no result\n");
		pua_dbf.free_result(pua_db, res);
		res = NULL;
		return 0;
	}

	LM_DBG("found %d db entries\n", res->n);

	do {
		for(i =0 ; i< res->n ; i++)
		{
			row = &res->rows[i];
			row_vals = ROW_VALUES(row);
			if(row_vals[expires_col].val.int_val < time(NULL))
				continue;

			pres_uri.s= (char*)row_vals[puri_col].val.string_val;
			pres_uri.len = strlen(pres_uri.s);

			LM_DBG("pres_uri= %.*s\n", pres_uri.len, pres_uri.s);

			memset(&etag,			 0, sizeof(str));
			memset(&tuple_id,		 0, sizeof(str));
			memset(&watcher_uri,	 0, sizeof(str));
			memset(&to_uri,          0, sizeof(str));
			memset(&call_id,		 0, sizeof(str));
			memset(&to_tag,			 0, sizeof(str));
			memset(&from_tag,		 0, sizeof(str));
			memset(&record_route,	 0, sizeof(str));
			memset(&pres_id,         0, sizeof(str));
			memset(&contact,         0, sizeof(str));
			memset(&remote_contact,  0, sizeof(str));
			memset(&extra_headers,   0, sizeof(str));

			pres_id.s= (char*)row_vals[pid_col].val.string_val;
			if(pres_id.s)
				pres_id.len = strlen(pres_id.s);

			if(row_vals[etag_col].val.string_val)
			{
				etag.s= (char*)row_vals[etag_col].val.string_val;
				etag.len = strlen(etag.s);

				tuple_id.s= (char*)row_vals[tuple_col].val.string_val;
				tuple_id.len = strlen(tuple_id.s);
			}

			if(row_vals[watcher_col].val.string_val)
			{
				watcher_uri.s= (char*)row_vals[watcher_col].val.string_val;
				watcher_uri.len = strlen(watcher_uri.s);

				to_uri.s= (char*)row_vals[touri_col].val.string_val;
				if(to_uri.s == NULL)
					to_uri = pres_uri;
				else
					to_uri.len = strlen(to_uri.s);
				LM_DBG("to_uri= %.*s\n", to_uri.len, to_uri.s);
				call_id.s= (char*)row_vals[callid_col].val.string_val;
				call_id.len = strlen(call_id.s);

				to_tag.s= (char*)row_vals[totag_col].val.string_val;
				to_tag.len = strlen(to_tag.s);

				from_tag.s= (char*)row_vals[fromtag_col].val.string_val;
				from_tag.len = strlen(from_tag.s);

				if(row_vals[record_route_col].val.string_val)
				{
					record_route.s= (char*)
						row_vals[record_route_col].val.string_val;
					record_route.len= strlen(record_route.s);
				}

				contact.s= (char*)row_vals[contact_col].val.string_val;
				contact.len = strlen(contact.s);

				remote_contact.s=
					(char*)row_vals[remote_contact_col].val.string_val;
				if(remote_contact.s)
					remote_contact.len = strlen(remote_contact.s);
			}
			extra_headers.s= (char*)row_vals[extra_headers_col].val.string_val;
			if(extra_headers.s)
				extra_headers.len= strlen(extra_headers.s);
			else
				extra_headers.len= 0;

			size= sizeof(ua_pres_t)+ sizeof(str)+ (pres_uri.len+ pres_id.len+
						tuple_id.len)* sizeof(char);

			if(watcher_uri.s)
				size+= sizeof(str)+ to_uri.len + watcher_uri.len+ call_id.len+ to_tag.len+
					from_tag.len+ record_route.len+ contact.len;

			p= (ua_pres_t*)shm_malloc(size);
			if(p== NULL)
			{
				LM_ERR("no more shared memmory");
				goto error;
			}
			memset(p, 0, size);
			size= sizeof(ua_pres_t);

			p->pres_uri= (str*)((char*)p+ size);
			size+= sizeof(str);
			p->pres_uri->s= (char*)p + size;
			memcpy(p->pres_uri->s, pres_uri.s, pres_uri.len);
			p->pres_uri->len= pres_uri.len;
			size+= pres_uri.len;

			if(pres_id.s)
			{
				CONT_COPY(p, p->id, pres_id);
			}

			if(watcher_uri.s && watcher_uri.len)
			{
				p->watcher_uri= (str*)((char*)p+ size);
				size+= sizeof(str);

				p->watcher_uri->s= (char*)p+ size;
				memcpy(p->watcher_uri->s, watcher_uri.s, watcher_uri.len);
				p->watcher_uri->len= watcher_uri.len;
				size+= watcher_uri.len;

				CONT_COPY(p, p->to_uri, to_uri);
				CONT_COPY(p, p->to_tag, to_tag);
				CONT_COPY(p, p->from_tag, from_tag);
				CONT_COPY(p, p->call_id, call_id);

				if(record_route.s && record_route.len)
				{
					CONT_COPY(p, p->record_route, record_route);
				}
				CONT_COPY(p, p->contact, contact);

				p->cseq= row_vals[cseq_col].val.int_val;

				p->remote_contact.s= (char*)shm_malloc(remote_contact.len);
				if(p->remote_contact.s== NULL)
				{
					LM_ERR("No more shared memory\n");
					goto error;
				}
				memcpy(p->remote_contact.s, remote_contact.s, remote_contact.len);
				p->remote_contact.len= remote_contact.len;

				p->version= row_vals[version_col].val.int_val;
			}

			LM_DBG("size= %d\n", size);
			p->event= row_vals[event_col].val.int_val;
			p->expires= row_vals[expires_col].val.int_val;
			p->desired_expires= row_vals[desired_expires_col].val.int_val;
			p->flag|=	row_vals[flag_col].val.int_val;

			memset(&p->etag, 0, sizeof(str));
			if(etag.s && etag.len)
			{
				/* alloc separately */
				p->etag.s= (char*)shm_malloc(etag.len);
				if(p->etag.s==  NULL)
				{
					LM_ERR("no more share memory\n");
					goto error;
				}
				memcpy(p->etag.s, etag.s, etag.len);
				p->etag.len= etag.len;
			}

			memset(&p->extra_headers, 0, sizeof(str));
			if(extra_headers.s && extra_headers.len)
			{
				/* alloc separately */
				p->extra_headers.s= (char*)shm_malloc(extra_headers.len);
				if(p->extra_headers.s==  NULL)
				{
					LM_ERR("no more share memory\n");
					goto error;
				}
				memcpy(p->extra_headers.s, extra_headers.s, extra_headers.len);
				p->extra_headers.len= extra_headers.len;
			}

			print_ua_pres(p);
			insert_htable(p);
		} /* end for(all rows)*/

		if (DB_CAPABILITY(pua_dbf, DB_CAP_FETCH)) {
			if(pua_dbf.fetch_result(pua_db, &res, no_rows)<0) {
				LM_ERR( "fetching rows (1)\n");
				goto error;
			}
		} else {
			break;
		}
	} while(RES_ROW_N(res)>0);

	pua_dbf.free_result(pua_db, res);
	res = NULL;

	if(pua_dbf.delete(pua_db, 0, 0 , 0, 0) < 0)
	{
		LM_ERR("while deleting information from db\n");
		goto error;
	}

	return 0;

error:
	if(res)
		pua_dbf.free_result(pua_db, res);

	if(p)
	{
		if(p->remote_contact.s) shm_free(p->remote_contact.s);
		if(p->extra_headers.s) shm_free(p->extra_headers.s);
		if(p->etag.s) shm_free(p->etag.s);
		shm_free(p);
	}
	return -1;
}
Beispiel #3
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;
}
Beispiel #4
0
/**
 * Diameter base protocol state-machine processing.
 * This function get's called for every event. It updates the states and can trigger
 * other events.
 * @param p - the peer for which the event happened
 * @param event - the event that happened
 * @param msg - if a Diameter message was received this is it, or NULL if not
 * @param peer_locked - if the peer lock is already aquired
 * @param sock - socket that this event happened on, or NULL if unrelated
 * @returns 1 on success, 0 on error. Also the peer states are updated
 */
int sm_process(peer *p,peer_event_t event,AAAMessage *msg,int peer_locked,int sock)
{
	int result_code;
	peer_event_t next_event;
	int msg_received=0;

	if (!peer_locked) lock_get(p->lock);
	LM_DBG("sm_process(): Peer %.*s State %s Event %s\n",
			p->fqdn.len,p->fqdn.s,dp_states[p->state],dp_events[event-101]);

	switch (p->state){
		case Closed:
			switch (event){
				case Start:
					p->state = Wait_Conn_Ack;
					next_event = I_Snd_Conn_Req(p);
					if (next_event==I_Rcv_Conn_NAck)
						sm_process(p,next_event,0,1,p->I_sock);
					else{
						/* wait for fd to be transmitted to the respective receiver,
						 * in order to get a send pipe opened */
					}
					break;
				case R_Conn_CER:
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					msg=0;
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						R_Disc(p);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case Stop:
					/* just ignore this state */
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case Wait_Conn_Ack:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					p->state = Wait_I_CEA;
					break;
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					p->state = Closed;
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Conn_Ack_Elect;
						p->r_cer = msg;
					}
					else {
						p->state = Closed;
						AAAFreeMessage(&msg);
						R_Disc(p);
						I_Disc(p);
					}
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_I_CEA:
			switch(event){
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					log_peer_list(L_INFO);
					break;
				case R_Conn_CER:
					if (p->r_cer) AAAFreeMessage(&(p->r_cer));
					R_Accept(p,sock);
					result_code = Process_CER(p,msg);
					if (result_code>=2000 && result_code<3000){
						p->state = Wait_Returns;
						if (Elect(p,msg)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_I_CEA Win Elect \n");
							sm_process(p,Win_Election,msg,1,sock);
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_I_CEA Lose Elect \n");
							p->r_cer = msg;
							sm_process(p,I_Peer_Disc,0,1,p->I_sock);
						}
					}
					else{
						Snd_CEA(p,msg,result_code,p->R_sock);
						R_Disc(p);
						I_Disc(p);
						p->state=Closed;
						break;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case I_Rcv_Non_CEA:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				case Timeout:
					Error(p,p->I_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_Conn_Ack_Elect:
			switch(event){
				case I_Rcv_Conn_Ack:
					I_Snd_CER(p);
					if (p->r_cer){
						p->state = Wait_Returns;
						if (Elect(p,p->r_cer)){
							// won the election = > I_Disc(), R_Send_CEA()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Win Elect \n");
							sm_process(p,Win_Election,p->r_cer,1,sock);
							p->r_cer = 0;
						} else {
							// lost the election => wait for I_Recv_CEA, then R_Disc()
							LM_INFO("sm_process():Wait_Conn_Ack_Elect Lose Elect \n");
							AAAFreeMessage(&p->r_cer);
						}
					} else {
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_Ack, No R-CER ! \n");
						p->state = Wait_I_CEA;
					}
					break;
				case I_Rcv_Conn_NAck:
					Cleanup(p,p->I_sock);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000)
							p->state = R_Open;
						else {
							R_Disc(p);
							p->state = Closed;
							//	p->state = R_Open; /* Or maybe I should disconnect it?*/
						}
					}else{
						LM_ERR("sm_process():Wait_Conn_Ack_Elect, I_Rcv_Conn_NAck No R-CER ! \n");
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_Conn_Ack;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Conn_Ack_Elect;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;

		case Wait_Returns:
			switch(event){
				case Win_Election:
					/* this is the Win Election -> I is dropped, R is kept */
					LM_INFO("sm_process():Wait_Returns Win Elect \n");
					I_Disc(p);
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000){
						p->state = R_Open;
					}else{
						R_Disc(p);
						p->state = Closed;
					}
					break;
				case I_Peer_Disc:
					I_Disc(p);
					if (p->r_cer){
						result_code = Process_CER(p,p->r_cer);
						Snd_CEA(p,p->r_cer,result_code,p->R_sock);
						p->r_cer=0;
						if (result_code>=2000 && result_code<3000){
							p->state = R_Open;
						}else{
							R_Disc(p);
							p->state = Closed;
						}
					}else {
						LM_ERR("sm_process():Wait_Returns, I_Peer_Disc No R-CER ! \n");
					}
					break;
				case I_Rcv_CEA:
					/* this is the Lost Election -> I is kept, R dropped */
					LM_INFO("sm_process():Wait_Returns Lost Elect \n");
					R_Disc(p);
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						Cleanup(p,p->I_sock);
						p->state = Closed;
					}
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Wait_I_CEA;
					break;
				case R_Conn_CER:
					R_Reject(p,p->R_sock);
					AAAFreeMessage(&msg);
					p->state = Wait_Returns;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case R_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = R_Open;
					break;
				case R_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = R_Open;
					break;
				case R_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->R_sock);
					p->state = R_Open;
					break;
				case R_Rcv_DWA:
					Process_DWA(p,msg);
					p->state = R_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = R_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case R_Rcv_DPR:
					Snd_DPA(p,msg,AAA_SUCCESS,p->R_sock);
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case R_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->R_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case R_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = R_Open;
					else {
						/*R_Disc(p);p.state = Closed;*/
						p->state = R_Open; /* Or maybe I should disconnect it?*/
					}
					log_peer_list(L_INFO);
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case I_Open:
			switch (event){
				case Send_Message:
					Snd_Message(p,msg);
					p->state = I_Open;
					break;
				case I_Rcv_Message:
					// delayed processing until out of the critical zone
					//Rcv_Process(p,msg);
					msg_received = 1;
					p->state = I_Open;
					break;
				case I_Rcv_DWR:
					result_code = Process_DWR(p,msg);
					Snd_DWA(p,msg,result_code,p->I_sock);
					p->state =I_Open;
					break;
				case I_Rcv_DWA:
					Process_DWA(p,msg);
					p->state =I_Open;
					break;
				case R_Conn_CER:
					R_Reject(p,sock);
					AAAFreeMessage(&msg);
					p->state = I_Open;
					break;
				case Stop:
					Snd_DPR(p);
					p->state = Closing;
					break;
				case I_Rcv_DPR:
					Snd_DPA(p,msg,2001,p->I_sock);
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					log_peer_list(L_INFO);
					break;
				case I_Rcv_CER:
					result_code = Process_CER(p,msg);
					Snd_CEA(p,msg,result_code,p->I_sock);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				case I_Rcv_CEA:
					result_code = Process_CEA(p,msg);
					if (result_code>=2000 && result_code<3000)
						p->state = I_Open;
					else {
						/*I_Disc(p);p.state = Closed;*/
						p->state = I_Open; /* Or maybe I should disconnect it?*/
					}
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
		case Closing:
			switch(event){
				case I_Rcv_DPA:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Rcv_DPA:
					R_Disc(p);
					p->state = Closed;
					break;
				case Timeout:
					if (p->I_sock>=0) Error(p,p->I_sock);
					if (p->R_sock>=0) Error(p,p->R_sock);
					p->state = Closed;
					break;
				case I_Peer_Disc:
					I_Disc(p);
					p->state = Closed;
					break;
				case R_Peer_Disc:
					R_Disc(p);
					p->state = Closed;
					break;
				default:
					LM_ERR("sm_process(): In state %s invalid event %s\n",
							dp_states[p->state],dp_events[event-101]);
					goto error;
			}
			break;
	}
	if (!peer_locked) lock_release(p->lock);

	if (msg_received)
		Rcv_Process(p,msg);

	return 1;
error:
	if (!peer_locked) lock_release(p->lock);
	return 0;
}
Beispiel #5
0
int h350_call_preferences(struct sip_msg* _msg, pv_elem_t* _avp_name_prefix)
{
	int           rc, i, avp_count = 0;
	struct berval **attr_vals;
	size_t        nmatch = 5;
	regmatch_t    pmatch[5];
	int       avp_name;
	int_str   avp_val;
	str           avp_val_str, avp_name_str,
	              avp_name_prefix_str, call_pref_timeout_str;
	int           call_pref_timeout;
	static char   call_pref_avp_name[AVP_NAME_STR_BUF_LEN];

        /*
         * get avp_name_prefix_str
         */
        if (pv_printf_s(_msg, _avp_name_prefix, &avp_name_prefix_str) != 0)
        {
                LM_ERR("pv_printf_s failed\n");
                return E_H350_INTERNAL;
        }


	/*
	 * get LDAP attribute values
	 */
	if ((rc = ldap_api.ldap_result_attr_vals(
			&h350_call_pref_name, &attr_vals)) < 0)
	{
		LM_ERR("Getting LDAP attribute values failed\n");
		return E_H350_INTERNAL;
	}

	if (rc > 0)
	{
		/* no LDAP values found */
		return E_H350_NO_SUCCESS;
	}

	/*
	 * loop through call pref values and add AVP(s)
	 */

	/* copy avp name prefix into call_pref_avp_name */
	if (avp_name_prefix_str.len < AVP_NAME_STR_BUF_LEN)
	{
		memcpy(call_pref_avp_name, avp_name_prefix_str.s, avp_name_prefix_str.len);
	} else
	{
		LM_ERR("AVP name prefix too long [%d] (max [%d])",
			avp_name_prefix_str.len,
			AVP_NAME_STR_BUF_LEN);
		return E_H350_INTERNAL;
	}

	for (i = 0; attr_vals[i] != NULL; i++)
	{
		if ((rc = regexec(call_pref_preg, attr_vals[i]->bv_val, nmatch, pmatch, 0)) != 0)
		{
			switch (rc)
			{
			case REG_NOMATCH:
				LM_INFO("no h350 call preference regex match for [%s]\n",
						attr_vals[i]->bv_val);
				continue;
			case REG_ESPACE:
				LM_ERR("regexec returned REG_ESPACE - out of memory\n");
			default:
				LM_ERR("regexec failed\n");
				ldap_api.ldap_value_free_len(attr_vals);
				return E_H350_INTERNAL;
			}
		}

		/* calculate call preference sip uri */
		if (avp_name_prefix_str.len + pmatch[2].rm_eo - pmatch[2].rm_so
			>= AVP_NAME_STR_BUF_LEN)
		{
			LM_ERR("AVP name too long for [%s]", attr_vals[i]->bv_val);
			continue;
		}
		avp_val_str.s = attr_vals[i]->bv_val + pmatch[1].rm_so;
		avp_val_str.len = pmatch[1].rm_eo - pmatch[1].rm_so;

		avp_val.s = avp_val_str;

		/* calculate call preference avp name */
		memcpy(	call_pref_avp_name + avp_name_prefix_str.len,
			attr_vals[i]->bv_val + pmatch[2].rm_so,
			pmatch[2].rm_eo - pmatch[2].rm_so);

		avp_name_str.s = call_pref_avp_name;
		avp_name_str.len = avp_name_prefix_str.len + pmatch[2].rm_eo - pmatch[2].rm_so;

		avp_name = get_avp_id(&avp_name_str);
		if (avp_name <= 0) {
			LM_ERR("cannot get avp id\n");
			continue;
		}

		/* add avp */
		if (add_avp(AVP_NAME_STR | AVP_VAL_STR, avp_name, avp_val) < 0)
		{
			LM_ERR("failed to create new AVP\n");
			ldap_api.ldap_value_free_len(attr_vals);
			return E_H350_INTERNAL;
		}

		avp_count++;

		/* check for call preference timeout */
		if ((pmatch[4].rm_eo - pmatch[4].rm_so) == 0)
		{
			continue;
		}

		/* calculate call preference timeout avp name */
		memcpy(	avp_name_str.s + avp_name_str.len, "_t", 2);
		avp_name_str.len += 2;
		avp_name = get_avp_id(&avp_name_str);
		if (avp_name <= 0) {
			LM_ERR("cannot get avp id\n");
			continue;
		}

		/* calculate timeout avp value */
		call_pref_timeout_str.s = attr_vals[i]->bv_val + pmatch[4].rm_so;
		call_pref_timeout_str.len = pmatch[4].rm_eo - pmatch[4].rm_so;
		if (str2sint(&call_pref_timeout_str, &call_pref_timeout) != 0)
		{
			LM_ERR("str2sint failed\n");
			ldap_api.ldap_value_free_len(attr_vals);
			return E_H350_INTERNAL;
		}
		call_pref_timeout = call_pref_timeout / 1000;

		/* add timeout avp */
		avp_val.n = call_pref_timeout;
		if (add_avp(AVP_NAME_STR, avp_name, avp_val) < 0)
		{
		        LM_ERR("failed to create new AVP\n");
			ldap_api.ldap_value_free_len(attr_vals);
                        return E_H350_INTERNAL;
		}
	}

	ldap_api.ldap_value_free_len(attr_vals);
	if (avp_count > 0)
	{
		return avp_count;
	} else
	{
		return E_H350_NO_SUCCESS;
	}
}
Beispiel #6
0
int split_frag(struct qm_block* qm, struct qm_frag* f, unsigned long new_size)
#endif
{
	unsigned long rest;
	struct qm_frag* n;
	struct qm_frag_end* end;
	
	rest=f->size-new_size;
#ifdef MEM_FRAG_AVOIDANCE
	if ((rest> (FRAG_OVERHEAD+QM_MALLOC_OPTIMIZE))||
		(rest>=(FRAG_OVERHEAD+new_size))){/* the residue fragm. is big enough*/
#else
	if (rest>(FRAG_OVERHEAD+MIN_FRAG_SIZE)){
#endif
		f->size=new_size;
		/*split the fragment*/
		end=FRAG_END(f);
		end->size=new_size;
		n=(struct qm_frag*)((char*)end+sizeof(struct qm_frag_end));
		n->size=rest-FRAG_OVERHEAD;
		FRAG_END(n)->size=n->size;
		FRAG_CLEAR_USED(n); /* never used */
		qm->real_used+=FRAG_OVERHEAD;
#ifdef DBG_QM_MALLOC
		end->check1=END_CHECK_PATTERN1;
		end->check2=END_CHECK_PATTERN2;
		/* frag created by malloc, mark it*/
		n->file=file;
		n->func=func;
		n->line=line;
		n->check=ST_CHECK_PATTERN;
#endif
		/* reinsert n in free list*/
		qm_insert_free(qm, n);
		return 0;
	}else{
			/* we cannot split this fragment any more */
		return -1;
	}
}



#ifdef DBG_QM_MALLOC
void* qm_malloc(void* qmp, unsigned long size,
					const char* file, const char* func, unsigned int line)
#else
void* qm_malloc(void* qmp, unsigned long size)
#endif
{
	struct qm_block* qm;
	struct qm_frag* f;
	int hash;
#ifdef DBG_QM_MALLOC
	unsigned int list_cntr;
#endif

	qm = (struct qm_block*)qmp;
	
#ifdef DBG_QM_MALLOC
	list_cntr = 0;
	MDBG("qm_malloc(%p, %lu) called from %s: %s(%d)\n", qm, size, file, func,
			line);
#endif
	/*malloc(0) should return a valid pointer according to specs*/
	if(unlikely(size==0)) size=4;
	/*size must be a multiple of 8*/
	size=ROUNDUP(size);
	if (size>(qm->size-qm->real_used)) return 0;

	/*search for a suitable free frag*/
#ifdef DBG_QM_MALLOC
	if ((f=qm_find_free(qm, size, &hash, &list_cntr))!=0){
#else
	if ((f=qm_find_free(qm, size, &hash))!=0){
#endif
		/* we found it!*/
		/*detach it from the free list*/
#ifdef DBG_QM_MALLOC
			qm_debug_frag(qm, f);
#endif
		qm_detach_free(qm, f);
		/*mark it as "busy"*/
		f->u.is_free=0;
		qm->free_hash[hash].no--;
		qm->ffrags--;
		/* we ignore split return */
#ifdef DBG_QM_MALLOC
		split_frag(qm, f, size, file, "fragm. from qm_malloc", line);
#else
		split_frag(qm, f, size);
#endif
		qm->real_used+=f->size;
		qm->used+=f->size;
		if (qm->max_real_used<qm->real_used)
			qm->max_real_used=qm->real_used;
#ifdef DBG_QM_MALLOC
		f->file=file;
		f->func=func;
		f->line=line;
		f->check=ST_CHECK_PATTERN;
		/*  FRAG_END(f)->check1=END_CHECK_PATTERN1;
			FRAG_END(f)->check2=END_CHECK_PATTERN2;*/
		MDBG("qm_malloc(%p, %lu) returns address %p frag. %p (size=%lu) on %d"
				" -th hit\n",
			 qm, size, (char*)f+sizeof(struct qm_frag), f, f->size, list_cntr );
#endif
#ifdef MALLOC_STATS
		if(qm->type==MEM_TYPE_PKG) {
			sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
		}
#endif
		return (char*)f+sizeof(struct qm_frag);
	}
	return 0;
}



#ifdef DBG_QM_MALLOC
void qm_free(void* qmp, void* p, const char* file, const char* func, 
				unsigned int line)
#else
void qm_free(void* qmp, void* p)
#endif
{
	struct qm_block* qm;
	struct qm_frag* f;
	unsigned long size;
#ifdef MEM_JOIN_FREE
	struct qm_frag* next;
	struct qm_frag* prev;
#endif /* MEM_JOIN_FREE*/

	qm = (struct qm_block*)qmp;

#ifdef DBG_QM_MALLOC
	MDBG("qm_free(%p, %p), called from %s: %s(%d)\n", qm, p, file, func, line);
#endif

	if (p==0) {
#ifdef DBG_QM_MALLOC
		LOG(L_WARN, "WARNING:qm_free: free(0) called from %s: %s(%d)\n", file, func, line);
#else
		LOG(L_WARN, "WARNING:qm_free: free(0) called\n");
#endif
		return;
	}

#ifdef DBG_QM_MALLOC
	if (p>(void*)qm->last_frag_end || p<(void*)qm->first_frag){
		LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!)"
				" called from %s: %s(%d) - aborting\n", p, file, func, line);
		if(likely(cfg_get(core, core_cfg, mem_safety)==0))
			abort();
		else return;
	}
#endif

	f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));

#ifdef DBG_QM_MALLOC
	qm_debug_frag(qm, f);
	if (f->u.is_free){
		LOG(L_CRIT, "BUG: qm_free: freeing already freed pointer (%p),"
				" called from %s: %s(%d), first free %s: %s(%ld) - aborting\n",
				p, file, func, line, f->file, f->func, f->line);
		if(likely(cfg_get(core, core_cfg, mem_safety)==0))
			abort();
		else return;
	}
	MDBG("qm_free: freeing frag. %p alloc'ed from %s: %s(%ld)\n",
			f, f->file, f->func, f->line);
#endif
	if (unlikely(f->u.is_free)){
		LM_INFO("freeing a free fragment (%p/%p) - ignore\n",
				f, p);
		return;
	}

	size=f->size;
	qm->used-=size;
	qm->real_used-=size;

#ifdef MEM_JOIN_FREE
	if(unlikely(cfg_get(core, core_cfg, mem_join)!=0)) {
		next=prev=0;
		/* mark this fragment as used (might fall into the middle of joined frags)
		  to give us an extra chance of detecting a double free call (if the joined
		  fragment has not yet been reused) */
		f->u.nxt_free=(void*)0x1L; /* bogus value, just to mark it as free */
		/* join packets if possible*/
		next=FRAG_NEXT(f);
		if (((char*)next < (char*)qm->last_frag_end) && (next->u.is_free)){
			/* join next packet */
#ifdef DBG_QM_MALLOC
			qm_debug_frag(qm, next);
#endif
			qm_detach_free(qm, next);
			size+=next->size+FRAG_OVERHEAD;
			qm->real_used-=FRAG_OVERHEAD;
			qm->free_hash[GET_HASH(next->size)].no--; /* FIXME slow */
			qm->ffrags--;
		}
	
		if (f > qm->first_frag){
			prev=FRAG_PREV(f);
			/*	(struct qm_frag*)((char*)f - (struct qm_frag_end*)((char*)f-
								sizeof(struct qm_frag_end))->size);*/
			if (prev->u.is_free){
				/* join prev packet */
#ifdef DBG_QM_MALLOC
				qm_debug_frag(qm, prev);
#endif
				qm_detach_free(qm, prev);
				size+=prev->size+FRAG_OVERHEAD;
				qm->real_used-=FRAG_OVERHEAD;
				qm->free_hash[GET_HASH(prev->size)].no--; /* FIXME slow */
				qm->ffrags--;
				f=prev;
			}
		}
		f->size=size;
		FRAG_END(f)->size=f->size;
	} /* if cfg_core->mem_join */
#endif /* MEM_JOIN_FREE*/
#ifdef DBG_QM_MALLOC
	f->file=file;
	f->func=func;
	f->line=line;
#endif
	qm_insert_free(qm, f);
#ifdef MALLOC_STATS
	if(qm->type==MEM_TYPE_PKG) {
		sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
	}
#endif
}



#ifdef DBG_QM_MALLOC
void* qm_realloc(void* qmp, void* p, unsigned long size,
					const char* file, const char* func, unsigned int line)
#else
void* qm_realloc(void* qmp, void* p, unsigned long size)
#endif
{
	struct qm_block* qm;
	struct qm_frag* f;
	unsigned long diff;
	unsigned long orig_size;
	struct qm_frag* n;
	void* ptr;

	qm = (struct qm_block*)qmp;

#ifdef DBG_QM_MALLOC
	MDBG("qm_realloc(%p, %p, %lu) called from %s: %s(%d)\n", qm, p, size,
			file, func, line);
	if ((p)&&(p>(void*)qm->last_frag_end || p<(void*)qm->first_frag)){
		LOG(L_CRIT, "BUG: qm_free: bad pointer %p (out of memory block!) - "
				"aborting\n", p);
		abort();
	}
#endif
	
	if (size==0) {
		if (p)
#ifdef DBG_QM_MALLOC
			qm_free(qm, p, file, func, line);
#else
			qm_free(qm, p);
#endif
		return 0;
	}
	if (p==0)
#ifdef DBG_QM_MALLOC
		return qm_malloc(qm, size, file, func, line);
#else
		return qm_malloc(qm, size);
#endif
	f=(struct qm_frag*) ((char*)p-sizeof(struct qm_frag));
#ifdef DBG_QM_MALLOC
	qm_debug_frag(qm, f);
	MDBG("qm_realloc: realloc'ing frag %p alloc'ed from %s: %s(%ld)\n",
			f, f->file, f->func, f->line);
	if (f->u.is_free){
		LOG(L_CRIT, "BUG:qm_realloc: trying to realloc an already freed "
				"pointer %p , fragment %p -- aborting\n", p, f);
		abort();
	}
#endif
	/* find first acceptable size */
	size=ROUNDUP(size);
	if (f->size > size){
		orig_size=f->size;
		/* shrink */
#ifdef DBG_QM_MALLOC
		MDBG("qm_realloc: shrinking from %lu to %lu\n", f->size, size);
		if(split_frag(qm, f, size, file, "fragm. from qm_realloc", line)!=0){
		MDBG("qm_realloc : shrinked successful\n");
#else
		if(split_frag(qm, f, size)!=0){
#endif
			/* update used sizes: freed the splited frag */
			/* split frag already adds FRAG_OVERHEAD for the newly created
			   free frag, so here we only need orig_size-f->size for real used
			 */
			qm->real_used-=(orig_size-f->size);
			qm->used-=(orig_size-f->size);
		}
		
	}else if (f->size < size){
		/* grow */
#ifdef DBG_QM_MALLOC
		MDBG("qm_realloc: growing from %lu to %lu\n", f->size, size);
#endif
			orig_size=f->size;
			diff=size-f->size;
			n=FRAG_NEXT(f);
			if (((char*)n < (char*)qm->last_frag_end) && 
					(n->u.is_free)&&((n->size+FRAG_OVERHEAD)>=diff)){
				/* join  */
				qm_detach_free(qm, n);
				qm->free_hash[GET_HASH(n->size)].no--; /*FIXME: slow*/
				qm->ffrags--;
				f->size+=n->size+FRAG_OVERHEAD;
				qm->real_used-=FRAG_OVERHEAD;
				FRAG_END(f)->size=f->size;
				/* end checks should be ok */
				/* split it if necessary */
				if (f->size > size ){
	#ifdef DBG_QM_MALLOC
					split_frag(qm, f, size, file, "fragm. from qm_realloc",
										line);
	#else
					split_frag(qm, f, size);
	#endif
				}
				qm->real_used+=(f->size-orig_size);
				qm->used+=(f->size-orig_size);
			}else{
				/* could not join => realloc */
	#ifdef DBG_QM_MALLOC
				ptr=qm_malloc(qm, size, file, func, line);
	#else
				ptr=qm_malloc(qm, size);
	#endif
				if (ptr){
					/* copy, need by libssl */
					memcpy(ptr, p, orig_size);
				}
	#ifdef DBG_QM_MALLOC
				qm_free(qm, p, file, func, line);
	#else
				qm_free(qm, p);
	#endif
				p=ptr;
			}
	}else{
		/* do nothing */
#ifdef DBG_QM_MALLOC
		MDBG("qm_realloc: doing nothing, same size: %lu - %lu\n",
				f->size, size);
#endif
	}
#ifdef DBG_QM_MALLOC
	MDBG("qm_realloc: returning %p\n", p);
#endif
#ifdef MALLOC_STATS
	if(qm->type==MEM_TYPE_PKG) {
		sr_event_exec(SREV_PKG_UPDATE_STATS, 0);
	}
#endif
	return p;
}


void qm_check(struct qm_block* qm)
{
	struct qm_frag* f;
	long fcount = 0;
	int memlog;
	
	memlog=cfg_get(core, core_cfg, memlog);
	LOG(memlog, "DEBUG: qm_check()\n");
	f = qm->first_frag;
	while ((char*)f < (char*)qm->last_frag_end) {
		fcount++;
		/* check struct qm_frag */
#ifdef DBG_QM_MALLOC
		if (f->check!=ST_CHECK_PATTERN){
			LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
					"beginning overwritten(%lx)!\n",
					f, (char*)f + sizeof(struct qm_frag),
					f->check);
			qm_status(qm);
			abort();
		};
#endif
		if (f + sizeof(struct qm_frag) + f->size + sizeof(struct qm_frag_end) > qm->first_frag + qm->size) {
			LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
				"bad size: %lu (frag end: %p > end of block: %p)\n",
				f, (char*)f + sizeof(struct qm_frag) + sizeof(struct qm_frag_end), f->size,
				f + sizeof(struct qm_frag) + f->size, qm->first_frag + qm->size);
			qm_status(qm);
			abort();
		}
		/* check struct qm_frag_end */
		if (FRAG_END(f)->size != f->size) {
			LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p) "
				"size in qm_frag and qm_frag_end does not match: frag->size=%lu, frag_end->size=%lu)\n",
				f, (char*)f + sizeof(struct qm_frag),
				f->size, FRAG_END(f)->size);
			qm_status(qm);
			abort();
		}
#ifdef DBG_QM_MALLOC
		if ((FRAG_END(f)->check1 != END_CHECK_PATTERN1) ||
			(FRAG_END(f)->check2 != END_CHECK_PATTERN2)) {
			LOG(L_CRIT, "BUG: qm_*: fragm. %p (address %p)"
						" end overwritten(%lx, %lx)!\n",
					f, (char*)f + sizeof(struct qm_frag), 
					FRAG_END(f)->check1, FRAG_END(f)->check2);
			qm_status(qm);
			abort();
		}
#endif
		f = FRAG_NEXT(f);
	}

	LOG(memlog, "DEBUG: qm_check: %lu fragments OK\n", fcount);
}

void qm_status(void* qmp)
{
	struct qm_block* qm;
	struct qm_frag* f;
	int i,j;
	int h;
	int unused;
	int memlog;
	int mem_summary;

	qm = (struct qm_block*)qmp;

	memlog=cfg_get(core, core_cfg, memlog);
	mem_summary=cfg_get(core, core_cfg, mem_summary);
	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "(%p):\n", qm);
	if (!qm) return;

	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ", "heap size= %lu\n",
			qm->size);
	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
			"used= %lu, used+overhead=%lu, free=%lu\n",
			qm->used, qm->real_used, qm->size-qm->real_used);
	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
			"max used (+overhead)= %lu\n", qm->max_real_used);
	
	if (mem_summary & 16) return;

	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
			"dumping all alloc'ed. fragments:\n");
	for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;f=FRAG_NEXT(f)
			,i++){
		if (! f->u.is_free){
			LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
					"   %3d. %c  address=%p frag=%p size=%lu used=%d\n",
				i,
				(f->u.is_free)?'a':'N',
				(char*)f+sizeof(struct qm_frag), f, f->size, FRAG_WAS_USED(f));
#ifdef DBG_QM_MALLOC
			LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
					"          %s from %s: %s(%ld)\n",
				(f->u.is_free)?"freed":"alloc'd", f->file, f->func, f->line);
			LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
					"         start check=%lx, end check= %lx, %lx\n",
				f->check, FRAG_END(f)->check1, FRAG_END(f)->check2);
#endif
		}
	}
	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
			"dumping free list stats :\n");
	for(h=0,i=0;h<QM_HASH_SIZE;h++){
		unused=0;
		for (f=qm->free_hash[h].head.u.nxt_free,j=0; 
				f!=&(qm->free_hash[h].head); f=f->u.nxt_free, i++, j++){
				if (!FRAG_WAS_USED(f)){
					unused++;
#ifdef DBG_QM_MALLOC
					LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
						"unused fragm.: hash = %3d, fragment %p,"
						" address %p size %lu, created from %s: %s(%lu)\n",
					    h, f, (char*)f+sizeof(struct qm_frag), f->size,
						f->file, f->func, f->line);
#endif
				}
		}

		if (j) LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
				"hash= %3d. fragments no.: %5d, unused: %5d\n"
					"\t\t bucket size: %9lu - %9ld (first %9lu)\n",
					h, j, unused, UN_HASH(h),
					((h<=QM_MALLOC_OPTIMIZE/ROUNDTO)?1:2)*UN_HASH(h),
					qm->free_hash[h].head.u.nxt_free->size
				);
		if (j!=qm->free_hash[h].no){
			LOG(L_CRIT, "BUG: qm_status: different free frag. count: %d!=%lu"
				" for hash %3d\n", j, qm->free_hash[h].no, h);
		}

	}
	LOG_(DEFAULT_FACILITY, memlog, "qm_status: ",
			"-----------------------------\n");
}


/* fills a malloc info structure with info about the block
 * if a parameter is not supported, it will be filled with 0 */
void qm_info(void* qmp, struct mem_info* info)
{
	struct qm_block* qm;

	qm = (struct qm_block*)qmp;

	memset(info,0, sizeof(*info));
	info->total_size=qm->size;
	info->min_frag=MIN_FRAG_SIZE;
	info->free=qm->size-qm->real_used;
	info->used=qm->used;
	info->real_used=qm->real_used;
	info->max_used=qm->max_real_used;
	info->total_frags=qm->ffrags;
}


/* returns how much free memory is available
 * it never returns an error (unlike fm_available) */
unsigned long qm_available(void* qmp)
{
	struct qm_block* qm;

	qm = (struct qm_block*)qmp;

	return qm->size-qm->real_used;
}



#ifdef DBG_QM_MALLOC

typedef struct _mem_counter{
	const char *file;
	const char *func;
	unsigned long line;
	
	unsigned long size;
	int count;
	
	struct _mem_counter *next;
} mem_counter;

static mem_counter* get_mem_counter(mem_counter **root, struct qm_frag* f)
{
	mem_counter *x;
	if (!*root) goto make_new;
	for(x=*root;x;x=x->next)
		if (x->file == f->file && x->func == f->func && x->line == f->line)
			return x;
make_new:	
	x = malloc(sizeof(mem_counter));
	x->file = f->file;
	x->func = f->func;
	x->line = f->line;
	x->count = 0;
	x->size = 0;
	x->next = *root;
	*root = x;
	return x;
}



void qm_sums(void* qmp)
{
	struct qm_block* qm;
	struct qm_frag* f;
	int i;
	mem_counter *root, *x;
	int memlog;
	
	qm = (struct qm_block*)qmp;

	root=0;
	if (!qm) return;
	
	memlog=cfg_get(core, core_cfg, memlog);
	LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
			"summarizing all alloc'ed. fragments:\n");
	
	for (f=qm->first_frag, i=0;(char*)f<(char*)qm->last_frag_end;
			f=FRAG_NEXT(f),i++){
		if (! f->u.is_free){
			x = get_mem_counter(&root,f);
			x->count++;
			x->size+=f->size;
		}
	}
	x = root;
	while(x){
		LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
				" count=%6d size=%10lu bytes from %s: %s(%ld)\n",
			x->count,x->size,
			x->file, x->func, x->line
			);
		root = x->next;
		free(x);
		x = root;
	}
	LOG_(DEFAULT_FACILITY, memlog, "qm_sums: ",
			"-----------------------------\n");
}
#else

void qm_sums(void* qm)
{
	return;
}
#endif /* DBG_QM_MALLOC */


/*memory manager core api*/
static char *_qm_mem_name = "q_malloc";

/* PKG - private memory API*/
static char *_qm_pkg_pool = 0;
static struct qm_block *_qm_pkg_block = 0;

/**
 * \brief Destroy memory pool
 */
void qm_malloc_destroy_pkg_manager(void)
{
	if (_qm_pkg_pool) {
		free(_qm_pkg_pool);
		_qm_pkg_pool = 0;
	}
	_qm_pkg_block = 0;
}

/**
 * \brief Init memory pool
 */
int qm_malloc_init_pkg_manager(void)
{
	sr_pkg_api_t ma;
	_qm_pkg_pool = malloc(pkg_mem_size);
	if (_qm_pkg_pool)
		_qm_pkg_block=qm_malloc_init(_qm_pkg_pool, pkg_mem_size, MEM_TYPE_PKG);
	if (_qm_pkg_block==0){
		LOG(L_CRIT, "could not initialize qm memory pool\n");
		fprintf(stderr, "Too much qm pkg memory demanded: %ld bytes\n",
						pkg_mem_size);
		return -1;
	}

	memset(&ma, 0, sizeof(sr_pkg_api_t));
	ma.mname = _qm_mem_name;
	ma.mem_pool = _qm_pkg_pool;
	ma.mem_block = _qm_pkg_block;
	ma.xmalloc = qm_malloc;
	ma.xfree = qm_free;
	ma.xrealloc = qm_realloc;
	ma.xstatus = qm_status;
	ma.xinfo = qm_info;
	ma.xavailable = qm_available;
	ma.xsums = qm_sums;
	ma.xdestroy = qm_malloc_destroy_pkg_manager;

	return pkg_init_api(&ma);
}


/* SHM - shared memory API*/
static void *_qm_shm_pool = 0;
static struct qm_block *_qm_shm_block = 0;

/*SHM wrappers to sync the access to memory block*/
#ifdef DBG_QM_MALLOC
void* qm_shm_malloc(void* qmp, unsigned long size,
					const char* file, const char* func, unsigned int line)
{
	void *r;
	shm_lock();
	r = qm_malloc(qmp, size, file, func, line);
	shm_unlock();
	return r;
}
Beispiel #7
0
/**
 * params:
 *   the filedes where the data was received.
 * returns:
 *   0 if this fd should be taken out of the poll_fd array bcause it already has AS name.
 *   fd if an AS was completed (returns the fd of the events socket)
 *   -1 if there was an error
 *   -2 if client disconnected and should be closed and taken outside the poll_fd array
 */
static int handle_unc_as_data(int fd)
{
   int i,j,k,len;
   char *name1;
   struct as_entry *as;
   /*first, we see if the data to read is from any of the uncompleted as's*/
   for(i=0;i<2*MAX_UNC_AS_NR ;i++)
      if(unc_as_t[i].valid && unc_as_t[i].fd==fd)
	 break;
   if(i==2*MAX_UNC_AS_NR){
      LM_ERR("has received an fd which is not in uncompleted AS array\n");
      return -1;
   }
   if(unc_as_t[i].flags & HAS_NAME){/*shouldn't happen, if it has a name, it shouldnt be in fdset[]*/
      LM_WARN("this shouldn't happen\n");
      return 0;/*already have a name, please take me out the uncompleted AS array*/
   }
   LM_DBG("Reading client name\n");

   if(-1==(len=read_name(fd,unc_as_t[i].name,MAX_AS_NAME))){
      /*this guy should be disconnected, it sent an AS_NAME too long*/
      LM_ERR("Bad name passed from fd\n");
      unc_as_t[i].valid=0;
      unc_as_t[i].flags=0;
      return -2;
   }else if(len==-2){
      LM_WARN("client disconnected\n");
      return -2;
   }
   name1=unc_as_t[i].name;

   /* Check the name isn't already taken */
   for(as=as_list;as;as=as->next){
      if(as->name.len==len && !memcmp(name1,as->name.s,len)){
	 if(as->connected){
	    LM_WARN("AppServer trying to connect with a name already taken (%.*s)\n",len,name1);
	    unc_as_t[i].valid=0;
	    unc_as_t[i].flags=0;
	    return -2;
	 }
	 break;
      }
   }
   if (!as) {
      LM_ERR("a client tried to connect which is not declared in config. script(%.*s)\n",len,name1);
      unc_as_t[i].valid=0;
      unc_as_t[i].flags=0;
      return -2;
   }
   unc_as_t[i].flags |= HAS_NAME;
   /* the loop's upper bound, 
    * if 'i' is in the lower part, then look for an unc_as in the upper part*/
   k=(i>=MAX_UNC_AS_NR?MAX_UNC_AS_NR:2*MAX_UNC_AS_NR);
   /* the loop's lower bound */
   for(j=(i>=MAX_UNC_AS_NR?0:MAX_UNC_AS_NR);j<k;j++)
      if(unc_as_t[j].valid && 
	    (unc_as_t[j].flags & HAS_NAME) && 
	    !strcmp(unc_as_t[i].name,unc_as_t[j].name))
	 break;
   LM_INFO("Fantastic, we have a new client: %s\n",unc_as_t[i].name);
   if(j==k)/* the unc_as peer's socket hasn't been found, just take this one out of fdset because it already has its name */
      return 0;/*take me out from fdset[]*/
   LM_INFO("EUREKA, we have a new completed AS: %s\n",unc_as_t[i].name);
   /* EUREKA ! we have a sweet pair of AS sockets, with the same name !!*/
   if(add_new_as(i<j?i:j,i<j?j:i,as)==-1){
      close(unc_as_t[j].fd);
      close(unc_as_t[i].fd);
      unc_as_t[j].valid=unc_as_t[i].valid=0;
      unc_as_t[j].flags=unc_as_t[i].flags=0;
      return -1;
   }
   unc_as_t[j].valid=unc_as_t[i].valid=0;
   unc_as_t[j].flags=unc_as_t[i].flags=0;
   return unc_as_t[i<j?i:j].fd;
}
Beispiel #8
0
void replicate_ucontact_update(urecord_t *r, ucontact_t *ct)
{
	str st;
	int rc;
	bin_packet_t packet;

	if (bin_init(&packet, &contact_repl_cap, REPL_UCONTACT_UPDATE, BIN_VERSION, 0) != 0) {
		LM_ERR("failed to replicate this event\n");
		return;
	}

	bin_push_str(&packet, r->domain);
	bin_push_str(&packet, &r->aor);
	bin_push_str(&packet, &ct->c);
	bin_push_str(&packet, &ct->callid);
	bin_push_str(&packet, &ct->user_agent);
	bin_push_str(&packet, &ct->path);
	bin_push_str(&packet, &ct->attr);
	bin_push_str(&packet, &ct->received);
	bin_push_str(&packet, &ct->instance);

	st.s = (char *) &ct->expires;
	st.len = sizeof ct->expires;
	bin_push_str(&packet, &st);

	st.s = (char *) &ct->q;
	st.len = sizeof ct->q;
	bin_push_str(&packet, &st);

	bin_push_str(&packet, ct->sock?&ct->sock->sock_str:NULL);
	bin_push_int(&packet, ct->cseq);
	bin_push_int(&packet, ct->flags);
	bin_push_int(&packet, ct->cflags);
	bin_push_int(&packet, ct->methods);

	st.s   = (char *)&ct->last_modified;
	st.len = sizeof ct->last_modified;
	bin_push_str(&packet, &st);

	st = store_serialize(ct->kv_storage);
	if (ZSTR(st))
		LM_ERR("oom\n");
	bin_push_str(&packet, &st);
	store_free_buffer(&st);

	if (cluster_mode == CM_FEDERATION_CACHEDB)
		rc = clusterer_api.send_all_having(&packet, location_cluster,
		                                   NODE_CMP_EQ_SIP_ADDR);
	else
		rc = clusterer_api.send_all(&packet, location_cluster);
	switch (rc) {
	case CLUSTERER_CURR_DISABLED:
		LM_INFO("Current node is disabled in cluster: %d\n", location_cluster);
		goto error;
	case CLUSTERER_DEST_DOWN:
		LM_INFO("All destinations in cluster: %d are down or probing\n",
			location_cluster);
		goto error;
	case CLUSTERER_SEND_ERR:
		LM_ERR("Error sending in cluster: %d\n", location_cluster);
		goto error;
	}

	bin_free_packet(&packet);
	return;

error:
	LM_ERR("replicate ucontact update failed\n");
	bin_free_packet(&packet);
}
Beispiel #9
0
static int receive_ucontact_insert(bin_packet_t *packet)
{
	static ucontact_info_t ci;
	static str d, aor, host, contact_str, callid,
		user_agent, path, attr, st, sock;
	udomain_t *domain;
	urecord_t *record;
	ucontact_t *contact;
	int rc, port, proto;

	memset(&ci, 0, sizeof ci);

	bin_pop_str(packet, &d);
	bin_pop_str(packet, &aor);

	if (find_domain(&d, &domain) != 0) {
		LM_ERR("domain '%.*s' is not local\n", d.len, d.s);
		goto error;
	}

	bin_pop_str(packet, &contact_str);

	bin_pop_str(packet, &st);
	memcpy(&ci.contact_id, st.s, sizeof ci.contact_id);

	bin_pop_str(packet, &callid);
	ci.callid = &callid;

	bin_pop_str(packet, &user_agent);
	ci.user_agent = &user_agent;

	bin_pop_str(packet, &path);
	ci.path = &path;

	bin_pop_str(packet, &attr);
	ci.attr = &attr;

	bin_pop_str(packet, &ci.received);
	bin_pop_str(packet, &ci.instance);

	bin_pop_str(packet, &st);
	memcpy(&ci.expires, st.s, sizeof ci.expires);

	bin_pop_str(packet, &st);
	memcpy(&ci.q, st.s, sizeof ci.q);

	bin_pop_str(packet, &sock);

	if (sock.s && sock.s[0]) {
		if (parse_phostport(sock.s, sock.len, &host.s, &host.len,
			&port, &proto) != 0) {
			LM_ERR("bad socket <%.*s>\n", sock.len, sock.s);
			goto error;
		}

		ci.sock = grep_sock_info(&host, (unsigned short) port,
			(unsigned short) proto);
		if (!ci.sock)
			LM_DBG("non-local socket <%.*s>\n", sock.len, sock.s);
	} else {
		ci.sock =  NULL;
	}

	bin_pop_int(packet, &ci.cseq);
	bin_pop_int(packet, &ci.flags);
	bin_pop_int(packet, &ci.cflags);
	bin_pop_int(packet, &ci.methods);

	bin_pop_str(packet, &st);
	memcpy(&ci.last_modified, st.s, sizeof ci.last_modified);

	if (skip_replicated_db_ops)
		ci.flags |= FL_MEM;

	lock_udomain(domain, &aor);

	if (get_urecord(domain, &aor, &record) != 0) {
		LM_INFO("failed to fetch local urecord - creating new one "
			"(ci: '%.*s') \n", callid.len, callid.s);

		if (insert_urecord(domain, &aor, &record, 1) != 0) {
			LM_ERR("failed to insert new record\n");
			unlock_udomain(domain, &aor);
			goto error;
		}
	}

	rc = get_ucontact(record, &contact_str, &callid, ci.cseq, &contact);
	switch (rc) {
	case -2:
		/* received data is consistent with what we have */
	case -1:
		/* received data is older than what we have */
		break;
	case 0:
		/* received data is newer than what we have */
		if (update_ucontact(record, contact, &ci, 1) != 0) {
			LM_ERR("failed to update ucontact (ci: '%.*s')\n", callid.len, callid.s);
			unlock_udomain(domain, &aor);
			goto error;
		}
		break;
	case 1:
		if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) {
			LM_ERR("failed to insert ucontact (ci: '%.*s')\n", callid.len, callid.s);
			unlock_udomain(domain, &aor);
			goto error;
		}
		break;
	}

	unlock_udomain(domain, &aor);
	return 0;

error:
	LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Beispiel #10
0
/*! \brief Convert the file content into regular expresions and store them in pcres */
static int load_pcres(int action)
{
	int i, j;
	FILE *f;
	char line[FILE_MAX_LINE];
	char **patterns = NULL;
	pcre *pcre_tmp = NULL;
	int pcre_size;
	int pcre_rc;
	const char *pcre_error;
	int pcre_erroffset;
	int num_pcres_tmp = 0;
	pcre **pcres_tmp = NULL;
	
	/* Get the lock */
	lock_get(reload_lock);
	
	if (!(f = fopen(file, "r"))) {
		LM_ERR("could not open file '%s'\n", file);
		goto err;
	}
	
	/* Array containing each pattern in the file */
	if ((patterns = pkg_malloc(sizeof(char*) * max_groups)) == 0) {
		LM_ERR("no more memory for patterns\n");
		fclose(f);
		goto err;
	}
	for (i=0; i<max_groups; i++) {
		patterns[i] = NULL;
	}
	for (i=0; i<max_groups; i++) {
		if ((patterns[i] = pkg_malloc(sizeof(char) * group_max_size)) == 0) {
			LM_ERR("no more memory for patterns[%d]\n", i);
			fclose(f);
			goto err;
		}
		memset(patterns[i], '\0', group_max_size);
	}
	
	/* Read the file and extract the patterns */
	memset(line, '\0', FILE_MAX_LINE);
	i = -1;
	while (fgets(line, FILE_MAX_LINE, f) != NULL) {
		
		/* Ignore comments and lines starting by space, tab, CR, LF */
		if(isspace(line[0]) || line[0]=='#') {
			memset(line, '\0', FILE_MAX_LINE);
			continue;
		}
		
		/* First group */
		if (i == -1 && line[0] != '[') {
			LM_ERR("first group must be initialized with [0] before any regular expression\n");
			fclose(f);
			goto err;
		}
		
		/* New group */
		if (line[0] == '[') {
			i++;
			/* Check if there are more patterns than the max value */
			if (i >= max_groups) {
				LM_ERR("max patterns exceeded\n");
				fclose(f);
				goto err;
			}
			/* Start the regular expression with '(' */
			patterns[i][0] = '(';
			memset(line, '\0', FILE_MAX_LINE);
			continue;
		}
		
		/* Check if the patter size is too big (aprox) */
		if (strlen(patterns[i]) + strlen(line) >= group_max_size - 2) {
			LM_ERR("pattern max file exceeded\n");
			fclose(f);
			goto err;
		}
		
		/* Append ')' at the end of the line */
		if (line[strlen(line) - 1] == '\n') {
			line[strlen(line)] = line[strlen(line) - 1];
			line[strlen(line) - 2] = ')';
		} else {
			/* This is the last char in the file and it's not \n */
			line[strlen(line)] = ')';
		}
		
		/* Append '(' at the beginning of the line */
		memcpy(patterns[i]+strlen(patterns[i]), "(", 1);
		
		/* Append the line to the current pattern */
		memcpy(patterns[i]+strlen(patterns[i]), line, strlen(line));
		
		memset(line, '\0', FILE_MAX_LINE);
	}
	num_pcres_tmp = i + 1;
	
	fclose(f);
	
	/* Fix the patterns */
	for (i=0; i < num_pcres_tmp; i++) {
		
		/* Convert empty groups in unmatcheable regular expression ^$ */
		if (strlen(patterns[i]) == 1) {
			patterns[i][0] = '^';
			patterns[i][1] = '$';
			patterns[i][2] = '\0';
			continue;
		}
		
		/* Delete possible '\n' at the end of the pattern */
		if (patterns[i][strlen(patterns[i])-1] == '\n') {
			patterns[i][strlen(patterns[i])-1] = '\0';
		}
		
		/* Replace '\n' with '|' (except at the end of the pattern) */
		for (j=0; j < strlen(patterns[i]); j++) {
			if (patterns[i][j] == '\n' && j != strlen(patterns[i])-1) {
				patterns[i][j] = '|';
			}
		}
		
		/* Add ')' at the end of the pattern */
		patterns[i][strlen(patterns[i])] = ')';
	}
	
	/* Log the group patterns */
	LM_INFO("num groups = %d\n", num_pcres_tmp);
	for (i=0; i < num_pcres_tmp; i++) {
		LM_INFO("<group[%d]>%s</group[%d]> (size = %i)\n", i, patterns[i], i, (int)strlen(patterns[i]));
	}
	
	/* Temporal pointer of pcres */
	if ((pcres_tmp = pkg_malloc(sizeof(pcre *) * num_pcres_tmp)) == 0) {
		LM_ERR("no more memory for pcres_tmp\n");
		goto err;
	}
	for (i=0; i<num_pcres_tmp; i++) {
		pcres_tmp[i] = NULL;
	}
	
	/* Compile the patters */
	for (i=0; i<num_pcres_tmp; i++) {
	
		pcre_tmp = pcre_compile(patterns[i], pcre_options, &pcre_error, &pcre_erroffset, NULL);
		if (pcre_tmp == NULL) {
			LM_ERR("pcre_tmp compilation of '%s' failed at offset %d: %s\n", patterns[i], pcre_erroffset, pcre_error);
			goto err;
		}
		pcre_rc = pcre_fullinfo(pcre_tmp, NULL, PCRE_INFO_SIZE, &pcre_size);
		if (pcre_rc) {
			printf("pcre_fullinfo on compiled pattern[%i] yielded error: %d\n", i, pcre_rc);
			goto err;
		}
		
		if ((pcres_tmp[i] = pkg_malloc(pcre_size)) == 0) {
			LM_ERR("no more memory for pcres_tmp[%i]\n", i);
			goto err;
		}
		
		memcpy(pcres_tmp[i], pcre_tmp, pcre_size);
		pcre_free(pcre_tmp);
		pkg_free(patterns[i]);
	}
	
	/* Copy to shared memory */
	if (action == RELOAD) {
		for(i=0; i<*num_pcres; i++) {  /* Use the previous num_pcres value */
			if (pcres[i]) {
				shm_free(pcres[i]);
			}
		}
		shm_free(pcres);
	}
	if ((pcres = shm_malloc(sizeof(pcre *) * num_pcres_tmp)) == 0) {
		LM_ERR("no more memory for pcres\n");
		goto err;
	}
	for (i=0; i<num_pcres_tmp; i++) {
		pcres[i] = NULL;
	}
	for (i=0; i<num_pcres_tmp; i++) {
		pcre_rc = pcre_fullinfo(pcres_tmp[i], NULL, PCRE_INFO_SIZE, &pcre_size);
		if ((pcres[i] = shm_malloc(pcre_size)) == 0) {
			LM_ERR("no more memory for pcres[%i]\n", i);
			goto err;
		}
		memcpy(pcres[i], pcres_tmp[i], pcre_size);
	}
	*num_pcres = num_pcres_tmp;
	*pcres_addr = pcres;

	/* Free used memory */
	for (i=0; i<num_pcres_tmp; i++) {
		pkg_free(pcres_tmp[i]);
	}
	pkg_free(pcres_tmp);
	pkg_free(patterns);
	lock_release(reload_lock);
	
	return 0;
	
	
err:
	if (patterns) {
		for(i=0; i<max_groups; i++) {
			if (patterns[i]) {
				pkg_free(patterns[i]);
			}
		}
		pkg_free(patterns);
	}
	if (pcres_tmp) {
		for (i=0; i<num_pcres_tmp; i++) {
			if (pcres_tmp[i]) {
				pkg_free(pcres_tmp[i]);
			}
		}
		pkg_free(pcres_tmp);
	}
	if (reload_lock) {
		lock_release(reload_lock);
	}
	if (action == START) {
		free_shared_memory();
	}
	return -1;
}
Beispiel #11
0
/**
 * init module function
 */
static int mod_init(void)
{
	sip_uri_t puri;
	char buri[MAX_URI_SIZE];

	if(th_sanity_checks!=0)
	{
		if(sanity_load_api(&scb)<0)
		{
			LM_ERR("cannot bind to sanity module\n");
			goto error;
		}
	}
	if(th_ip.len<=0)
	{
		LM_ERR("mask IP parameter is invalid\n");
		goto error;
	}

	if(th_ip.len + 32 >= MAX_URI_SIZE) {
		LM_ERR("mask address is too long\n");
		goto error;
	}
	memcpy(buri, "sip:", 4);
	memcpy(buri+4, th_ip.s, th_ip.len);
	buri[th_ip.len+8] = '\0';

	if(parse_uri(buri, th_ip.len+4, &puri)<0) {
		LM_ERR("mask uri is invalid\n");
		goto error;
	}
	if(check_self(&puri.host, puri.port_no, 0)==1)
	{
		th_mask_addr_myself = 1;
		LM_INFO("mask address matches myself [%.*s]\n",
				th_ip.len, th_ip.s);
	}

	/* 'SIP/2.0/UDP ' + ip + ';' + param + '=' + prefix (+ '\0') */
	th_via_prefix.len = 12 + th_ip.len + 1 + th_vparam_name.len + 1
		+ th_vparam_prefix.len;
	th_via_prefix.s = (char*)pkg_malloc(th_via_prefix.len+1);
	if(th_via_prefix.s==NULL)
	{
		LM_ERR("via prefix parameter is invalid\n");
		goto error;
	}
	/* 'sip:' + ip + ';' + param + '=' + prefix (+ '\0') */
	th_uri_prefix.len = 4 + th_ip.len + 1 + th_uparam_name.len + 1
		+ th_uparam_prefix.len;
	th_uri_prefix.s = (char*)pkg_malloc(th_uri_prefix.len+1);
	if(th_uri_prefix.s==NULL)
	{
		LM_ERR("uri prefix parameter is invalid\n");
		goto error;
	}
	/* build via prefix */
	memcpy(th_via_prefix.s, "SIP/2.0/UDP ", 12);
	memcpy(th_via_prefix.s+12, th_ip.s, th_ip.len);
	th_via_prefix.s[12+th_ip.len] = ';';
	memcpy(th_via_prefix.s+12+th_ip.len+1, th_vparam_name.s,
			th_vparam_name.len);
	th_via_prefix.s[12+th_ip.len+1+th_vparam_name.len] = '=';
	memcpy(th_via_prefix.s+12+th_ip.len+1+th_vparam_name.len+1,
			th_vparam_prefix.s, th_vparam_prefix.len);
	th_via_prefix.s[th_via_prefix.len] = '\0';
	LM_DBG("VIA prefix: [%s]\n", th_via_prefix.s);
	/* build uri prefix */
	memcpy(th_uri_prefix.s, "sip:", 4);
	memcpy(th_uri_prefix.s+4, th_ip.s, th_ip.len);
	th_uri_prefix.s[4+th_ip.len] = ';';
	memcpy(th_uri_prefix.s+4+th_ip.len+1, th_uparam_name.s, th_uparam_name.len);
	th_uri_prefix.s[4+th_ip.len+1+th_uparam_name.len] = '=';
	memcpy(th_uri_prefix.s+4+th_ip.len+1+th_uparam_name.len+1,
			th_uparam_prefix.s, th_uparam_prefix.len);
	th_uri_prefix.s[th_uri_prefix.len] = '\0';
	LM_DBG("URI prefix: [%s]\n", th_uri_prefix.s);

	th_mask_init();
	sr_event_register_cb(SREV_NET_DATA_IN, th_msg_received);
	sr_event_register_cb(SREV_NET_DATA_OUT, th_msg_sent);
#ifdef USE_TCP
	tcp_set_clone_rcvbuf(1);
#endif
	return 0;
error:
	return -1;
}
Beispiel #12
0
/* read from a socket, an AAA message buffer */
int do_read( int socket, rd_buf_t *p)
{
	unsigned char  *ptr;
	unsigned int   wanted_len, len;
	int n;

	if (p->buf==0)
	{
		wanted_len = sizeof(p->first_4bytes) - p->buf_len;
		ptr = ((unsigned char*)&(p->first_4bytes)) + p->buf_len;
	}
	else
	{
		wanted_len = p->first_4bytes - p->buf_len;
		ptr = p->buf + p->buf_len;
	}

	while( (n=recv( socket, ptr, wanted_len, MSG_DONTWAIT ))>0 ) 
	{
//		LM_DBG("(sock=%d)  -> n=%d (expected=%d)\n", p->sock,n,wanted_len);
		p->buf_len += n;
		if (n<wanted_len)
		{
			//LM_DBG("only %d bytes read from %d expected\n",n,wanted_len);
			wanted_len -= n;
			ptr += n;
		}
		else 
		{
			if (p->buf==0)
			{
				/* I just finished reading the first 4 bytes from msg */
				len = ntohl(p->first_4bytes)&0x00ffffff;
				if (len<AAA_MSG_HDR_SIZE || len>MAX_AAA_MSG_SIZE)
				{
					LM_ERR("(sock=%d): invalid message "
						"length read %u (%x)\n", socket, len, p->first_4bytes);
					goto error;
				}
				//LM_DBG("message length = %d(%x)\n",len,len);
				if ( (p->buf=pkg_malloc(len))==0  )
				{
					LM_ERR("no more pkg memory\n");
					goto error;
				}
				*((unsigned int*)p->buf) = p->first_4bytes;
				p->buf_len = sizeof(p->first_4bytes);
				p->first_4bytes = len;
				/* update the reading position and len */
				ptr = p->buf + p->buf_len;
				wanted_len = p->first_4bytes - p->buf_len;
			}
			else
			{
				/* I finished reading the whole message */
				LM_DBG("(sock=%d): whole message read (len=%d)!\n",
					socket, p->first_4bytes);
				return CONN_SUCCESS;
			}
		}
	}

	if (n==0)
	{
		LM_INFO("(sock=%d): FIN received\n", socket);
		return CONN_CLOSED;
	}
	if ( n==-1 && errno!=EINTR && errno!=EAGAIN )
	{
		LM_ERR("(on sock=%d): n=%d , errno=%d (%s)\n",
			socket, n, errno, strerror(errno));
		goto error;
	}
error:
	return CONN_ERROR;
}
Beispiel #13
0
/* change the r-uri if it is a PSTN format */
static int prefix2domain(struct sip_msg* msg, int mode, int sd_en)
{
	str *d, p, all={"*",1};
	int plen;
	struct sip_uri uri;

	if(msg==NULL)
	{
		LM_ERR("received null msg\n");
		return -1;
	}

	/* parse the uri, if not yet */
	if(msg->parsed_uri_ok==0)
		if(parse_sip_msg_uri(msg)<0)
		{
			LM_ERR("failed to parse the R-URI\n");
			return -1;
		}

    /* if the user part begin with the prefix for PSTN users, extract the code*/
	if (msg->parsed_uri.user.len<=0)
	{
		LM_DBG("user part of the message is empty\n");
		return -1;
	}

	if(prefix.len>0)
	{
		if (msg->parsed_uri.user.len<=prefix.len)
		{
			LM_DBG("user part is less than prefix\n");
			return -1;
		}
		if(strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0)
		{
			LM_DBG("PSTN prefix did not matched\n");
			return -1;
		}
	}

	if(prefix.len>0 && prefix.len < msg->parsed_uri.user.len
			&& strncasecmp(prefix.s, msg->parsed_uri.user.s, prefix.len)!=0)
	{
		LM_DBG("PSTN prefix did not matched\n");
		return -1;

	}

	p.s   = msg->parsed_uri.user.s + prefix.len;
	p.len = msg->parsed_uri.user.len - prefix.len;

	lock_start_read( pdt_lock );

	if(sd_en==2)
	{
		/* take the domain from  FROM uri as sdomain */
		if(parse_from_header(msg)<0 ||  msg->from == NULL
				|| get_from(msg)==NULL)
		{
			LM_ERR("cannot parse FROM header\n");
			goto error;
		}

		memset(&uri, 0, sizeof(struct sip_uri));
		if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0)
		{
			LM_ERR("failed to parse From uri\n");
			goto error;
		}

		/* find the domain that corresponds to this prefix */
		plen = 0;
		if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL)
		{
			plen = 0;
			if((d=pdt_get_domain(*_ptree, &all, &p, &plen))==NULL)
			{
				LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
				goto error;
			}
		}
	} else if(sd_en==1) {
		/* take the domain from  FROM uri as sdomain */
		if(parse_from_header(msg)<0 ||  msg->from == NULL
				|| get_from(msg)==NULL)
		{
			LM_ERR("ERROR cannot parse FROM header\n");
			goto error;
		}

		memset(&uri, 0, sizeof(struct sip_uri));
		if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len , &uri)<0)
		{
			LM_ERR("failed to parse From uri\n");
			goto error;
		}

		/* find the domain that corresponds to this prefix */
		plen = 0;
		if((d=pdt_get_domain(*_ptree, &uri.host, &p, &plen))==NULL)
		{
			LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
			goto error;
		}
	} else {
		/* find the domain that corresponds to this prefix */
		plen = 0;
		if((d=pdt_get_domain(*_ptree, &all, &p, &plen))==NULL)
		{
			LM_INFO("no prefix found in [%.*s]\n", p.len, p.s);
			goto error;
		}
	}

	/* update the new uri */
	if(update_new_uri(msg, plen, d, mode)<0)
	{
		LM_ERR("new_uri cannot be updated\n");
		goto error;
	}

	lock_stop_read( pdt_lock );
	return 1;

error:
	lock_stop_read( pdt_lock );
	return -1;
}
Beispiel #14
0
/**
 * init module function
 */
static int mod_init(void)
{
	LM_INFO("initializing...\n");

	init_db_url( db_url , 0 /*cannot be null*/);
	db_table.len = strlen(db_table.s);
	sdomain_column.len = strlen(sdomain_column.s);
	prefix_column.len = strlen(prefix_column.s);
	domain_column.len = strlen(domain_column.s);
	prefix.len = strlen(prefix.s);

	pdt_char_list.len = strlen(pdt_char_list.s);
	if(pdt_char_list.len<=0)
	{
		LM_ERR("invalid pdt char list\n");
		return -1;
	}
	LM_INFO("pdt_char_list=%s \n",pdt_char_list.s);

	/* binding to mysql module */
	if(db_bind_mod(&db_url, &pdt_dbf))
	{
		LM_ERR("database module not found\n");
		return -1;
	}

	if (!DB_CAPABILITY(pdt_dbf, DB_CAP_ALL))
	{
		LM_ERR("database module does not "
		    "implement all functions needed by the module\n");
		return -1;
	}

	/* open a connection with the database */
	db_con = pdt_dbf.init(&db_url);
	if(db_con==NULL)
	{
		LM_ERR("failed to connect to the database\n");
		return -1;
	}

	if (pdt_dbf.use_table(db_con, &db_table) < 0)
	{
		LM_ERR("failed to use_table\n");
		goto error1;
	}
	LM_DBG("database connection opened successfully\n");

	/* create & init lock */
	if ((pdt_lock = lock_init_rw()) == NULL) {
		LM_CRIT("failed to init lock\n");
		goto error1;
	}

	/* tree pointer in shm */
	_ptree = (pdt_tree_t**)shm_malloc( sizeof(pdt_tree_t*) );
	if (_ptree==0) {
		LM_ERR("out of shm mem for pdtree\n");
		goto error1;
	}
	*_ptree=0;

	/* loading all information from database */
	if(pdt_load_db()!=0)
	{
		LM_ERR("cannot load info from database\n");
		goto error1;
	}

	pdt_dbf.close(db_con);
	db_con = 0;

#if 0
	pdt_print_tree(*_ptree);
#endif

	/* success code */
	return 0;

error1:
	if (pdt_lock)
	{
		lock_destroy_rw( pdt_lock );
		pdt_lock = 0;
	}
	if(_ptree!=0)
		shm_free(_ptree);

	if(db_con!=NULL)
	{
		pdt_dbf.close(db_con);
		db_con = 0;
	}
	return -1;
}
/*
 * main binary packet UDP receiver loop
 */
static void bin_receive_loop(void)
{
	int rcv_bytes;
	struct receive_info ri;
	struct packet_cb_list *p;
	str name;

	ri.bind_address = bind_address;
	ri.dst_port = bind_address->port_no;
	ri.dst_ip = bind_address->address;
	ri.proto = PROTO_UDP;
	ri.proto_reserved1 = ri.proto_reserved2 = 0;

	for (;;) {
		rcv_bytes = recvfrom(bind_address->socket, rcv_buf, BUF_SIZE,
							 0, NULL, NULL);
		if (rcv_bytes == -1) {
			if (errno == EAGAIN) {
				LM_DBG("packet with bad checksum received\n");
				continue;
			}

			LM_ERR("recvfrom: [%d] %s\n", errno, strerror(errno));
			if (errno == EINTR || errno == EWOULDBLOCK || errno == ECONNREFUSED)
				continue;

			return;
		}

		rcv_end = rcv_buf + rcv_bytes;

		if (rcv_bytes < MIN_BIN_PACKET_SIZE) {
			LM_INFO("received invalid packet: len = %d\n", rcv_bytes);
			continue;
		}

		if (!is_valid_bin_packet(rcv_buf)) {
			LM_WARN("Invalid binary packet header! First 10 bytes: %.*s\n",
					10, rcv_buf);
			continue;
		}

		if (!has_valid_checksum(rcv_buf, rcv_bytes)) {
			LM_WARN("binary packet checksum test failed!\n");
			continue;
		}

		get_name(rcv_buf, name);
		cpos = name.s + name.len + CMD_FIELD_SIZE;

		/* packet will be now processed by a specific module */
		for (p = reg_modules; p; p = p->next) {
			if (p->module.len == name.len &&
			    memcmp(name.s, p->module.s, name.len) == 0) {

				LM_DBG("binary Packet CMD: %d. Module: %.*s\n",
						bin_rcv_type, name.len, name.s);

				p->cbf(bin_rcv_type);

				break;
			}
		}
	}
}
Beispiel #16
0
static int receive_ucontact_update(bin_packet_t *packet)
{
	static ucontact_info_t ci;
	static str d, aor, host, contact_str, callid,
		user_agent, path, attr, st, sock;
	udomain_t *domain;
	urecord_t *record;
	ucontact_t *contact;
	int port, proto;
	int rc;

	memset(&ci, 0, sizeof ci);

	bin_pop_str(packet, &d);
	bin_pop_str(packet, &aor);

	if (find_domain(&d, &domain) != 0) {
		LM_ERR("domain '%.*s' is not local\n", d.len, d.s);
		goto error;
	}

	bin_pop_str(packet, &contact_str);

	bin_pop_str(packet, &callid);
	ci.callid = &callid;

	bin_pop_str(packet, &user_agent);
	ci.user_agent = &user_agent;

	bin_pop_str(packet, &path);
	ci.path = &path;

	bin_pop_str(packet, &attr);
	ci.attr = &attr;

	bin_pop_str(packet, &ci.received);
	bin_pop_str(packet, &ci.instance);

	bin_pop_str(packet, &st);
	memcpy(&ci.expires, st.s, sizeof ci.expires);

	bin_pop_str(packet, &st);
	memcpy(&ci.q, st.s, sizeof ci.q);

	bin_pop_str(packet, &sock);

	if (sock.s && sock.s[0]) {
		if (parse_phostport(sock.s, sock.len, &host.s, &host.len,
			&port, &proto) != 0) {
			LM_ERR("bad socket <%.*s>\n", sock.len, sock.s);
			goto error;
		}

		ci.sock = grep_sock_info(&host, (unsigned short) port,
			(unsigned short) proto);
		if (!ci.sock)
			LM_DBG("non-local socket <%.*s>\n", sock.len, sock.s);
	} else {
		ci.sock = NULL;
	}

	bin_pop_int(packet, &ci.cseq);
	bin_pop_int(packet, &ci.flags);
	bin_pop_int(packet, &ci.cflags);
	bin_pop_int(packet, &ci.methods);

	bin_pop_str(packet, &st);
	memcpy(&ci.last_modified, st.s, sizeof ci.last_modified);

	bin_pop_str(packet, &st);
	ci.packed_kv_storage = &st;

	if (skip_replicated_db_ops)
		ci.flags |= FL_MEM;

	lock_udomain(domain, &aor);

	/* failure in retrieving a urecord may be ok, because packet order in UDP
	 * is not guaranteed, so update commands may arrive before inserts */
	if (get_urecord(domain, &aor, &record) != 0) {
		LM_INFO("failed to fetch local urecord - create new record and contact"
			" (ci: '%.*s')\n", callid.len, callid.s);

		if (insert_urecord(domain, &aor, &record, 1) != 0) {
			LM_ERR("failed to insert urecord\n");
			unlock_udomain(domain, &aor);
			goto error;
		}

		if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) {
			LM_ERR("failed (ci: '%.*s')\n", callid.len, callid.s);
			unlock_udomain(domain, &aor);
			goto error;
		}
	} else {
		rc = get_ucontact(record, &contact_str, &callid, ci.cseq + 1, &contact);
		if (rc == 1) {
			LM_INFO("contact '%.*s' not found, inserting new (ci: '%.*s')\n",
				contact_str.len, contact_str.s, callid.len, callid.s);

			if (insert_ucontact(record, &contact_str, &ci, &contact, 1) != 0) {
				LM_ERR("failed to insert ucontact (ci: '%.*s')\n",
					callid.len, callid.s);
				unlock_udomain(domain, &aor);
				goto error;
			}
		} else if (rc == 0) {
			if (update_ucontact(record, contact, &ci, 1) != 0) {
				LM_ERR("failed to update ucontact '%.*s' (ci: '%.*s')\n",
					contact_str.len, contact_str.s, callid.len, callid.s);
				unlock_udomain(domain, &aor);
				goto error;
			}
		} /* XXX: for -2 and -1, the master should have already handled
			 these errors - so we can skip them - razvanc */
	}

	unlock_udomain(domain, &aor);

	return 0;

error:
	LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Beispiel #17
0
/*! Parse the curlcon module parameter
 *
 *	Syntax:
 *		name => proto://user:password@server/url/url
 *		name => proto://server/url/url
 *		name => proto://server/url/url;param=value;param=value
 *
 *		the url is very much like CURLs syntax
 *		the url is a base url where you can add local address
 */
int curl_parse_param(char *val)
{
	str name	= STR_NULL;;
	str schema	= STR_NULL;
	str url		= STR_NULL;
	str username	= STR_NULL;
	str password	= STR_NULL;
	str params	= STR_NULL;
	str failover	= STR_NULL;
	unsigned int timeout	= default_connection_timeout;
	str useragent   = { default_useragent, strlen(default_useragent) };
	unsigned int http_follow_redirect = default_http_follow_redirect;

	str in;
	char *p;
	char *u;
	param_t *conparams = NULL;
	curl_con_t *cc;

	username.len = 0;
	password.len = 0;
	LM_INFO("curl modparam parsing starting\n");
	LM_DBG("modparam curlcon: %s\n", val);

	/* parse: name=>http_url*/
	in.s = val;
	in.len = strlen(in.s);
	p = in.s;

	/* Skip white space */
	while(p < in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
		p++;
	}
	if(p > in.s+in.len || *p=='\0') {
		goto error;
	}

	/* This is the connection name */
	name.s = p;
	/* Skip to whitespace */
	while(p < in.s + in.len)
	{
		if(*p=='=' || *p==' ' || *p=='\t' || *p=='\n' || *p=='\r') {
			break;
		}
		p++;
	}
	if(p > in.s+in.len || *p=='\0') {
		goto error;
	}
	name.len = p - name.s;
	if(*p != '=')
	{
		/* Skip whitespace */
		while(p<in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
			p++;
		}
		if(p>in.s+in.len || *p=='\0' || *p!='=') {
			goto error;
		}
	}
	p++;
	if(*p != '>') {
		goto error;
	}
	p++;
	/* Skip white space again */
	while(p < in.s+in.len && (*p==' ' || *p=='\t' || *p=='\n' || *p=='\r')) {
		p++;
	}
	schema.s = p;
	/* Skip to colon ':' */
	while(p < in.s + in.len)
	{
		if(*p == ':') {
			break;
		}
		p++;
	}
	if(*p != ':') {
		goto error;
	}
	schema.len = p - schema.s;
	p++;	/* Skip the colon */
	/* Skip two slashes */
	if(*p != '/') {
		goto error;
	}
	p++;
	if(*p != '/') {
		goto error;
	}
	p++;
	/* We are now at the first character after :// */
	url.s = p;
	url.len = in.len + (int)(in.s - p);
	u = p;

	/* Now check if there is a @ character. If so, we need to parse the username
	   and password */
	/* Skip to at-sign '@' */
	while(p < in.s + in.len)
	{
		if(*p == '@') {
			break;
		}
		p++;
	}
	if (*p == '@') {
		/* We have a username and possibly password - parse them out */
		username.s = u;
		while (u < p) {
			if (*u == ':') {
				break;
			}
			u++;
		}
		username.len = u - username.s;

		/* We either have a : or a @ */
		if (*u == ':') {
			u++;
			/* Go look for password */
			password.s = u;
			while (u < p) {
				u++;
			}
			password.len = u - password.s;
		}
		p++;	/* Skip the at sign */
		url.s = p;
		url.len = in.len + (int)(in.s - p);
	}
	/* Reset P to beginning of URL and look for parameters - starting with ; */
	p = url.s;
	/* Skip to ';' or end of string */
	while(p < url.s + url.len)
	{
		if(*p == ';') {
			/* Cut off URL at the ; */
			url.len = (int)(p - url.s);
			break;
		}
		p++;
	}
	if (*p == ';') {
		/* We have parameters */
		str tok;
		int_str ival;
		int itype;
		param_t *pit = NULL;

		/* Adjust the URL length */

		p++;		/* Skip the ; */
		params.s = p;
		params.len = in.len + (int) (in.s - p);
		param_hooks_t phooks;

		if (parse_params(&params, CLASS_ANY, &phooks, &conparams) < 0)
                {
                        LM_ERR("CURL failed parsing curlcon parameters value\n");
                        goto error;
                }

		/* Have parameters */
		for (pit = conparams; pit; pit=pit->next)
		{
			tok = pit->body;
			if(pit->name.len==12 && strncmp(pit->name.s, "httpredirect", 12)==0) {
				if(str2int(&tok, &http_follow_redirect) != 0) {
					/* Bad value */
					LM_DBG("curl connection [%.*s]: httpredirect bad value. Using default\n", name.len, name.s);
					http_follow_redirect = default_http_follow_redirect;
				}
				if (http_follow_redirect != 0 && http_follow_redirect != 1) {
					LM_DBG("curl connection [%.*s]: httpredirect bad value. Using default\n", name.len, name.s);
					http_follow_redirect = default_http_follow_redirect;
				}
				LM_DBG("curl [%.*s] - httpredirect [%d]\n", pit->name.len, pit->name.s, http_follow_redirect);
			} else if(pit->name.len==7 && strncmp(pit->name.s, "timeout", 7)==0) {
				if(str2int(&tok, &timeout)!=0) {
					/* Bad timeout */
					LM_DBG("curl connection [%.*s]: timeout bad value. Using default\n", name.len, name.s);
					timeout = default_connection_timeout;
				}
				LM_DBG("curl [%.*s] - timeout [%d]\n", pit->name.len, pit->name.s, timeout);
			} else if(pit->name.len==9 && strncmp(pit->name.s, "useragent", 9)==0) {
				useragent = tok;
				LM_DBG("curl [%.*s] - useragent [%.*s]\n", pit->name.len, pit->name.s,
						useragent.len, useragent.s);
			} else if(pit->name.len==8 && strncmp(pit->name.s, "failover", 8)==0) {
				failover = tok;
				LM_DBG("curl [%.*s] - failover [%.*s]\n", pit->name.len, pit->name.s,
						failover.len, failover.s);
			} else {
				LM_ERR("curl Unknown parameter [%.*s] \n", pit->name.len, pit->name.s);
			}
		}
	}

	/* The URL ends either with nothing or parameters. Parameters start with ; */
	

	LM_DBG("cname: [%.*s] url: [%.*s] username [%.*s] password [%.*s] failover [%.*s] timeout [%d] useragent [%.*s]\n", 
			name.len, name.s, url.len, url.s, username.len, username.s,
			password.len, password.s, failover.len, failover.s, timeout, useragent.len, useragent.s);

	if(conparams != NULL) {
		free_params(conparams);
	}

	cc =  curl_init_con(&name);
	if (cc == NULL) {
		return -1;
	}
	cc->username = username;
	cc->password = password;
	cc->schema = schema;
	cc->failover = failover;
	cc->useragent = useragent;
	cc->url = url;
	cc->timeout = timeout;
	cc->http_follow_redirect = http_follow_redirect;
	return 0;

error:
	LM_ERR("invalid curl parameter [%.*s] at [%d]\n", in.len, in.s, (int)(p-in.s));

	if(conparams != NULL) {
		free_params(conparams);
	}
	return -1;
}
Beispiel #18
0
/* Module initialization function */
static int mod_init(void)
{
	
	LM_DBG("init curl module\n");

	/* Initialize curl */
	if (curl_global_init(CURL_GLOBAL_ALL)) {
		LM_ERR("curl_global_init failed\n");
		return -1;
	}
	curl_info = curl_version_info(CURLVERSION_NOW);

	if(curl_init_rpc() < 0)
        {
                LM_ERR("failed to register RPC commands\n");
                return -1;
        }

	if (init_shmlock() != 0) {
		LM_CRIT("cannot initialize shmlock.\n");
		return -1;
	}

	curl_counter_init();
	counter_add(connections, curl_connection_count());

	if (default_tls_version >= CURL_SSLVERSION_LAST) {
		LM_WARN("tlsversion %d unsupported value. Using libcurl default\n", default_tls_version);
		default_tls_version = CURL_SSLVERSION_DEFAULT;
	}
	if (http_client_config_file.s != NULL)
	{
		if (http_client_load_config(&http_client_config_file) < 0)
		{
			LM_ERR("Failed to load http_client connections from [%.*s]\n", http_client_config_file.len, http_client_config_file.s);
			return -1;
		}
	}

	if (default_connection_timeout == 0) {
		LM_ERR("CURL connection timeout set to zero. Using default 4 secs\n");
		default_connection_timeout = 4;
	}
	if (default_http_proxy_port == 0) {
		LM_INFO("HTTP proxy port set to 0. Disabling HTTP proxy\n");
	}


	LM_DBG("**** init curl module done. Curl version: %s SSL %s\n", curl_info->version, curl_info->ssl_version);
	LM_DBG("**** init curl: Number of connection objects: %d \n", curl_connection_count());
	LM_DBG("**** init curl: User Agent: %.*s \n", default_useragent.len, default_useragent.s);
	LM_DBG("**** init curl: HTTPredirect: %d \n", default_http_follow_redirect);
	LM_DBG("**** init curl: Client Cert: %.*s Key %.*s\n", default_tls_clientcert.len, default_tls_clientcert.s, default_tls_clientkey.len, default_tls_clientkey.s);
	LM_DBG("**** init curl: CA Cert: %s \n", default_tls_cacert);
	LM_DBG("**** init curl: Cipher Suites: %.*s \n", default_cipher_suite_list.len, default_cipher_suite_list.s);
	LM_DBG("**** init curl: SSL Version: %d \n", default_tls_version);
	LM_DBG("**** init curl: verifypeer: %d verifyhost: %d\n", default_tls_verify_peer, default_tls_verify_host);
	LM_DBG("**** init curl: HTTP Proxy: %s Port %d\n", default_http_proxy, default_http_proxy_port);

	LM_DBG("Extra: Curl supports %s %s %s \n",
			(curl_info->features & CURL_VERSION_SSL ? "SSL" : ""),
			(curl_info->features & CURL_VERSION_IPV6 ? "IPv6" : ""),
			(curl_info->features & CURL_VERSION_IDN ? "IDN" : "")
		 );
	return 0;
}
Beispiel #19
0
/** Main loop for the Event Dispatcher process.
 * 
 */
int dispatcher_main_loop(void)
{
   struct pollfd poll_fds[3+MAX_AS_NR],*poll_tmp;
   int clean_index,i,j,k,fd,poll_events=0,socks[2],chld_status;
   int as_nr,unc_as_nr;
   pid_t chld;
   struct timeval last_ping,now;
   struct as_entry *as;

   sig_flag=0;
   is_dispatcher=1;
   as_nr=0;

   timerclear(&last_ping);
   timerclear(&now);
   signal(SIGCHLD,seas_sighandler);
   signal(SIGTERM,seas_sighandler);
   signal(SIGUSR1,seas_sighandler);
   signal(SIGINT, seas_sighandler);
   signal(SIGKILL,seas_sighandler);

   strcpy(whoami,"Seas Event Dispatcher process");
   /*I set process_no to -1 because otherwise, the logging process confuses this process with another from SER
    * (see LM_*() and dprint() and my_pid())*/
   process_no = -1;

   if(open_server_sockets(seas_listen_ip,seas_listen_port,socks)==-1){
      LM_ERR("unable to open server sockets on dispatcher\n");
      return -1;
   }
   for(i=0;i<2;i++){
      poll_fds[i].fd=socks[i];
      poll_fds[i].revents=0;
      poll_fds[i].events=POLLIN;
   }
   poll_fds[2].fd=read_pipe;
   poll_fds[2].revents=0;
   poll_fds[2].events=POLLIN;/*pollhup ?*/

   poll_events=0;
   unc_as_nr=0;

   if(use_ha)
      spawn_pinger();

   while(1){
      if(sig_flag==SIGCHLD){
	 while ((chld=waitpid( -1, &chld_status, WNOHANG ))>0) {
	    if (WIFEXITED(chld_status)){
	       LM_INFO("child process %d exited normally, status=%d\n",
				   chld,WEXITSTATUS(chld_status));
	    }else if (WIFSIGNALED(chld_status)) {
	       LM_INFO("child process %d exited by a signal %d\n",
				   chld,WTERMSIG(chld_status));
	    }else if (WIFSTOPPED(chld_status)) 
	       LM_INFO("child process %d stopped by a signal %d\n",
				   chld,WSTOPSIG(chld_status));
	    for (as=as_list;as;as=as->next) {
	       if(as->type!=AS_TYPE)
		  continue;
	       if(as->u.as.action_pid==chld){
		  for(i=0;i<as_nr && ((poll_fds[3+i].fd)!=(as->u.as.event_fd));i++)
		     ;
		  if(i==as_nr){
		     LM_ERR("Either the pinger has died or BUG found..\n");
		     continue;
		  }
		  /*overwrite the obsolete 'i' position with the next position*/
		  for(j=3+i;j<(as_nr+unc_as_nr+3-1);i++){
		     poll_fds[j].fd=poll_fds[j+1].fd;
		     poll_fds[j].events=poll_fds[j+1].events;
		     poll_fds[j].revents=poll_fds[j+1].revents;
		  }
		  close(as->u.as.event_fd);/*close the socket fd*/
		  if (as->u.as.ev_buffer.s) {
		     pkg_free(as->u.as.ev_buffer.s);
		     as->u.as.ev_buffer.s=(char *)0;
		     as->u.as.ev_buffer.len=0;
		  }
		  as->u.as.event_fd=as->u.as.action_fd=-1;
		  as->connected=0;
		  destroy_pingtable(&as->u.as.jain_pings);
		  destroy_pingtable(&as->u.as.servlet_pings);
		  as_nr--;
		  LM_WARN("client [%.*s] leaving (Action Dispatcher Process died !)\n",
				  as->name.len,as->name.s);
		  break;
	       }/*if(action_pid==chld)*/
	    }/*for(as=as_list;as;as=as->next)*/
	 }/*while(waitpid(-1)>0)*/
      }else if (sig_flag) {
	 LM_WARN("received signal != sigchld(%d)\n",sig_flag);
	  }
      sig_flag=0;
      clean_index=0;
      LM_INFO("polling [2 ServSock] [1 pipe] [%d App Servers]"
			  " [%d Uncomplete AS]\n",as_nr,unc_as_nr);
      poll_events = poll(poll_fds,3+unc_as_nr+as_nr,-1);
      if (poll_events == -1) {
	 if(errno==EINTR){
	    /*handle the case a child has died.
	     * It will be done in the next iteration in if(seas_sigchld_received)*/
	    continue;
	 }
	 if(errno==EBADF){
	    LM_ERR("invalid file descriptor pased to poll (%s)\n",
				strerror(errno));
	    return -1;/*??*/
	 }
	 /* errors */
	 LM_ERR("poll'ing:%s\n",strerror(errno));
	 poll_events=0;
	 continue;
      } else if (poll_events == 0) {/*timeout*/
	 continue;
      } else {/*there are events !*/
	 /*handle connections from server sockets*/
	 for(i=0;i<2;i++){
	    if(poll_fds[i].revents)
	       poll_events--;
	    if(poll_fds[i].revents & POLLIN){
	       poll_fds[i].revents &= (~POLLIN);
	       if((fd=new_as_connect(socks[i],i==0?'e':'a'))>=0){
		  poll_tmp=&poll_fds[3+as_nr+unc_as_nr];
		  poll_tmp->fd=fd;
		  poll_tmp->events=POLLIN|POLLHUP;
		  unc_as_nr++;
		  LM_DBG("Have new %s client\n",i==0?"event":"action");
	       }else{
		  LM_ERR("accepting connection from AS\n");
	       }
	    }
	 }
	 /*handle data from pipe*/
	 if(poll_fds[2].revents & POLLIN){
	    poll_fds[2].revents &= (~POLLIN);
	    poll_events--;
	    if(dispatch_relay()<0){
	       LM_ERR("dispatch_relay returned -1"
		     "should clean-up table\n");
	    }
	 }
	 /*now handle receive data from completed AS*/
	 clean_index=0;
	 LM_DBG("Scanning data from %d AS\n",as_nr);
	 for(i=0;(i<as_nr) && poll_events;i++){
	    clean_index=0;
	    poll_tmp=&poll_fds[3+i];
	    if(poll_tmp->revents)
	       poll_events--;
	    if(poll_tmp->revents & POLLIN){
	       LM_DBG("POLLIN found in AS #%i\n",i);
	       poll_tmp->revents &= (~POLLIN);
	       switch(handle_as_data(poll_tmp->fd)){
		  case -2:/*read returned 0 bytes, an AS client is leaving*/
		     clean_index=1;
		     break;
		  case -1:/*shouldnt happen*/
		     LM_ERR("reading from AS socket\n");
		     break;
		  case 0:/* event_response received and processed*/
		     break;
		  default:
		     LM_WARN("unknown return type from handle_as_data\n");
	       }
	    }
	    if(clean_index || (poll_tmp->revents & POLLHUP)){
	       LM_DBG("POLHUP or read==0 found in %i AS \n",i);
	       clean_index=0;
	       poll_tmp->revents = 0;
	       for(as=as_list;as;as=as->next){
		  if(as->type==CLUSTER_TYPE)
		     continue;
		  if(as->connected && (as->u.as.event_fd == poll_tmp->fd)){
		     close(poll_tmp->fd);/*close the socket fd*/
		     /*TODO  we should send a signal to the Action Dispatcher !!!*/
		     as->connected=0;
		     as_nr--;
		     /*overwrite the obsolete 'i' position with the next position*/
		     for(k=i;k<(as_nr+unc_as_nr);k++){
			j=3+k;
			poll_fds[j].fd=poll_fds[j+1].fd;
			poll_fds[j].events=poll_fds[j+1].events;
			poll_fds[j].revents=poll_fds[j+1].revents;
		     }
		     --i;
		     LM_WARN("client %.*s leaving !!!\n",as->name.len,as->name.s);
		     break;
		  }
	       }
	       if (!as) {
		  LM_ERR("the leaving client was not found in the as_list\n");
		   }
	    }
	 }
	 /*now handle data sent from uncompleted AS*/
	 LM_DBG("Scanning data from %d uncomplete AS \n",unc_as_nr);
	 clean_index=0;
	 for(i=0;i<unc_as_nr && poll_events;i++){
	    poll_tmp=&poll_fds[3+as_nr+i];
	    if(poll_tmp->revents)
	       poll_events--;
	    if(poll_tmp->revents & POLLIN){
	       LM_DBG("POLLIN found in %d uncomplete AS \n",i);
	       poll_tmp->revents &= (~POLLIN);
	       fd=handle_unc_as_data(poll_tmp->fd);
	       if(fd>0){
		  /* there's a new AS, push the uncomplete poll_fds up and set the AS */
		  for(k=i;k>0;k--){
		     j=3+as_nr+k;
		     poll_fds[j].fd=poll_fds[j-1].fd;
		     poll_fds[j].events=poll_fds[j-1].events;
		     poll_fds[j].revents=poll_fds[j-1].revents;
		  }
		  poll_fds[3+as_nr].fd=fd;
		  poll_fds[3+as_nr].events=POLLIN|POLLHUP;
		  poll_fds[3+as_nr].revents=0;
		  as_nr++;/*not very sure if this is thread-safe*/
		  unc_as_nr--;
	       }else if(fd<=0){/* pull the upper set of uncomplete AS down and take this one out*/
		  poll_tmp->revents=0;
		  for(k=i;k<(unc_as_nr-1);k++){
		     j=3+as_nr+k;
		     poll_fds[j].fd=poll_fds[j+1].fd;
		     poll_fds[j].events=poll_fds[j+1].events;
		     poll_fds[j].revents=poll_fds[j+1].revents;
		  }
		  unc_as_nr--;
		  /** we decrement i so that pulling down the upper part of the unc_as array so that
		   * it doesn't affect our for loop */
		  i--;
	       }
	    }
	    if(poll_tmp->revents & POLLHUP){
	       LM_DBG("POLLHUP found in %d uncomplete AS \n",i);
	       close(poll_tmp->fd);
	       for(k=i;k<(unc_as_nr-1);k++){
		  j=3+as_nr+k;
		  poll_fds[j].fd=poll_fds[j+1].fd;
		  poll_fds[j].events=poll_fds[j+1].events;
		  poll_fds[j].revents=poll_fds[j+1].revents;
	       }
	       unc_as_nr--;
	       i--;
	       poll_tmp->revents = 0;
	    }
	 }/*for*/
      }/*else ...(poll_events>0)*/
   }/*while(1)*/
}
Beispiel #20
0
static int mod_init(void)
{
	LM_INFO("initializing...\n");
	suffix.len = strlen(suffix.s);
	return 0;
}
Beispiel #21
0
int mt_table_spec(char* val)
{
	param_t* params_list = NULL;
	param_hooks_t phooks;
	param_t *pit=NULL;
	m_tree_t tmp;
	m_tree_t *it, *prev, *ndl;
	str s;
	
	if(val==NULL)
		return -1;

	if(!shm_initialized())
	{
		LM_ERR("shm not intialized - cannot define mtree now\n");
		return 0;
	}

	s.s = val;
	s.len = strlen(s.s);
	if(s.s[s.len-1]==';')
		s.len--;
	if (parse_params(&s, CLASS_ANY, &phooks, &params_list)<0)
		return -1;
	memset(&tmp, 0, sizeof(m_tree_t));
	for (pit = params_list; pit; pit=pit->next)
	{
		if (pit->name.len==4
				&& strncasecmp(pit->name.s, "name", 4)==0) {
			tmp.tname = pit->body;
		} else if(pit->name.len==4
				&& strncasecmp(pit->name.s, "type", 4)==0) {
			str2sint(&pit->body, &tmp.type);
		}  else if(pit->name.len==7
				&& strncasecmp(pit->name.s, "dbtable", 7)==0) {
			tmp.dbtable = pit->body;
		}
	}
	if(tmp.tname.s==NULL)
	{
		LM_ERR("invalid mtree name\n");
		goto error;
	}
	if(tmp.dbtable.s==NULL)
	{
		LM_INFO("no table name - default mtree\n");
		tmp.dbtable.s = "mtree";
		tmp.dbtable.len = 5;
	}
	if ((tmp.type != 0) && (tmp.type != 1) && (tmp.type != 2)) {
	    LM_ERR("unknown tree type <%d>\n", tmp.type);
	    goto error;
	}
	
	/* check for same tree */
	if(_ptree == 0)
	{
		/* tree list head in shm */
		_ptree = (m_tree_t**)shm_malloc( sizeof(m_tree_t*) );
		if (_ptree==0)
		{
			LM_ERR("out of shm mem for ptree\n");
			goto error;
		}
		*_ptree=0;
	}
	it = *_ptree;
	prev = NULL;
	/* search the it position before which to insert new tvalue */
	while(it!=NULL && str_strcmp(&it->tname, &tmp.tname)<0)
	{	
		prev = it;
		it = it->next;
	}

	/* found */
	if(it!=NULL && str_strcmp(&it->tname, &tmp.tname)==0)
	{
		LM_ERR("duplicate tree with name [%s]\n", tmp.tname.s);
		goto error; 
	}
	/* add new tname*/
	if(it==NULL || str_strcmp(&it->tname, &tmp.tname)>0)
	{
                LM_DBG("adding new tname [%s]\n", tmp.tname.s);

		ndl = mt_init_tree(&tmp.tname, &tmp.dbtable, tmp.type);
		if(ndl==NULL)
		{
			LM_ERR("no more shm memory\n");
			goto error; 
		}

		ndl->next = it;
		
		/* new tvalue must be added as first element */
		if(prev==NULL)
			*_ptree = ndl;
		else
			prev->next=ndl;

	}

	free_params(params_list);
	return 0;
error:
	free_params(params_list);
	return -1;
}
Beispiel #22
0
/**
 * start_async_http_req - performs an HTTP request, stores results in pvars
 *		- TCP connect phase is synchronous, due to libcurl limitations
 *		- TCP read phase is asynchronous, thanks to the libcurl multi interface
 *
 * @msg:		sip message struct
 * @method:		HTTP verb
 * @url:		HTTP URL to be queried
 * @req_body:	Body of the request (NULL if not needed)
 * @req_ctype:	Value for the "Content-Type: " header of the request (same as ^)
 * @out_handle: CURL easy handle used to perform the transfer
 * @body:	    reply body; gradually reallocated as data arrives
 * @ctype:	    will eventually hold the last "Content-Type" header of the reply
 */
int start_async_http_req(struct sip_msg *msg, enum rest_client_method method,
					     char *url, char *req_body, char *req_ctype,
					     CURL **out_handle, str *body, str *ctype)
{
	CURL *handle;
	CURLcode rc;
	CURLMcode mrc;
	fd_set rset, wset, eset;
	int max_fd, fd, i;
	long busy_wait, timeout;
	long retry_time, check_time = 5; /* 5ms looping time */
	int msgs_in_queue;
	CURLMsg *cmsg;

	if (transfers == FD_SETSIZE) {
		LM_ERR("too many ongoing tranfers: %d\n", FD_SETSIZE);
		clean_header_list;
		return ASYNC_NO_IO;
	}

	handle = curl_easy_init();
	if (!handle) {
		LM_ERR("Init curl handle failed!\n");
		clean_header_list;
		return ASYNC_NO_IO;
	}

	w_curl_easy_setopt(handle, CURLOPT_URL, url);

	switch (method) {
	case REST_CLIENT_POST:
		w_curl_easy_setopt(handle, CURLOPT_POST, 1);
		w_curl_easy_setopt(handle, CURLOPT_POSTFIELDS, req_body);

		if (req_ctype) {
			sprintf(print_buff, "Content-Type: %s", req_ctype);
			header_list = curl_slist_append(header_list, print_buff);
			w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);
		}
		break;
	case REST_CLIENT_GET:
		break;

	default:
		LM_ERR("Unsupported rest_client_method: %d, defaulting to GET\n", method);
	}

	if (header_list)
		w_curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header_list);

	w_curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT, connection_timeout);
	w_curl_easy_setopt(handle, CURLOPT_TIMEOUT, curl_timeout);

	w_curl_easy_setopt(handle, CURLOPT_VERBOSE, 1);
	w_curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
	w_curl_easy_setopt(handle, CURLOPT_STDERR, stdout);

	w_curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func);
	w_curl_easy_setopt(handle, CURLOPT_WRITEDATA, body);

	if (ctype) {
		w_curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_func);
		w_curl_easy_setopt(handle, CURLOPT_HEADERDATA, ctype);
	}

	if (ssl_capath)
		w_curl_easy_setopt(handle, CURLOPT_CAPATH, ssl_capath);

	if (!ssl_verifypeer)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0L);

	if (!ssl_verifyhost)
		w_curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0L);

	curl_multi_add_handle(multi_handle, handle);

	timeout = connection_timeout_ms;
	/* obtain a read fd in "connection_timeout" seconds at worst */
	for (timeout = connection_timeout_ms; timeout > 0; timeout -= busy_wait) {
		mrc = curl_multi_perform(multi_handle, &running_handles);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_perform: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		mrc = curl_multi_timeout(multi_handle, &retry_time);
		if (mrc != CURLM_OK) {
			LM_ERR("curl_multi_timeout: %s\n", curl_multi_strerror(mrc));
			goto error;
		}

		if (retry_time == -1) {
			LM_INFO("curl_multi_timeout() returned -1, pausing %ldms...\n",
					sleep_on_bad_timeout);
			busy_wait = sleep_on_bad_timeout;
			usleep(1000UL * busy_wait);
			continue;
		}

		if (retry_time > connection_timeout_ms)
			LM_INFO("initial TCP connect: we must wait at least %ldms! Please "
			        "consider increasing 'connection_timeout'!\n", retry_time);

		busy_wait = retry_time < timeout ? retry_time : timeout;

		/**
		 * libcurl is currently stuck in internal operations (connect)
		 *    we have to wait a bit until we receive a read fd
		 */
		for (i = 0; i < busy_wait; i += check_time) {
			/* transfer may have already been completed!! */
			while ((cmsg = curl_multi_info_read(multi_handle, &msgs_in_queue))) {
				if (cmsg->easy_handle == handle && cmsg->msg == CURLMSG_DONE) {
					LM_DBG("done, no need for async!\n");

					clean_header_list;
					*out_handle = handle;
					return ASYNC_SYNC;
				}
			}

			FD_ZERO(&rset);
			mrc = curl_multi_fdset(multi_handle, &rset, &wset, &eset, &max_fd);
			if (mrc != CURLM_OK) {
				LM_ERR("curl_multi_fdset: %s\n", curl_multi_strerror(mrc));
				goto error;
			}

			if (max_fd != -1) {
				for (fd = 0; fd <= max_fd; fd++) {
					if (FD_ISSET(fd, &rset)) {

						LM_DBG(" >>>>>>>>>> fd %d ISSET(read)\n", fd);
						if (is_new_transfer(fd)) {
							LM_DBG("add fd to read list: %d\n", fd);
							add_transfer(fd);
							goto success;
						}
					}
				}
			}

			usleep(1000UL * check_time);
		}
	}

	LM_ERR("timeout while connecting to '%s' (%ld sec)\n", url, connection_timeout);
	goto error;

success:
	clean_header_list;
	*out_handle = handle;
	return fd;

error:
	mrc = curl_multi_remove_handle(multi_handle, handle);
	if (mrc != CURLM_OK)
		LM_ERR("curl_multi_remove_handle: %s\n", curl_multi_strerror(mrc));

cleanup:
	clean_header_list;
	curl_easy_cleanup(handle);
	return ASYNC_NO_IO;
}
Beispiel #23
0
int h350_auth_lookup(
        struct sip_msg* _msg,
        pv_elem_t* _digest_username,
        struct h350_auth_lookup_avp_params* _avp_specs)
{
	str                digest_username,
	                   digest_username_escaped,
	                   digest_password;
	static char        digest_username_buf[DIGEST_USERNAME_BUF_SIZE];
	struct berval      **attr_vals = NULL;
	int                username_avp_name, password_avp_name;
	int_str avp_val;
	unsigned short     username_avp_type, password_avp_type;
	int                rc, ld_result_count;

	/*
	 * get digest_username str
	 */
	if (_digest_username)
	{
                if (pv_printf_s(_msg, _digest_username, &digest_username) != 0)
		{
                        LM_ERR("pv_printf_s failed\n");
                        return E_H350_INTERNAL;
                }
        } else
	{
		LM_ERR("empty digest username\n");
		return E_H350_NO_SUCCESS;
	}

	/*
	 * get AVP names for username and password
	 */

	if (pv_get_avp_name(	_msg,
				&(_avp_specs->username_avp_spec.pvp),
				&username_avp_name,
				&username_avp_type)
		!= 0)
	{
		LM_ERR("error getting AVP name - pv_get_avp_name failed\n");
		return E_H350_INTERNAL;
	}

	if (pv_get_avp_name(_msg,
						&(_avp_specs->password_avp_spec.pvp),
						&password_avp_name,
						&password_avp_type)
                != 0)
        {
                LM_ERR("error getting AVP name - pv_get_avp_name failed\n");
                return E_H350_INTERNAL;
        }

	/*
	 * search for sip digest username in H.350, store digest password
	 */

	/* ldap filter escape digest username */
	digest_username_escaped.s = digest_username_buf;
	digest_username_escaped.len = DIGEST_USERNAME_BUF_SIZE - 1;
	if (ldap_api.ldap_rfc4515_escape(
		&digest_username,
		&digest_username_escaped,
		0)
	   )
        {
                LM_ERR("ldap_rfc4515_escape() failed\n");
                return E_H350_INTERNAL;
        }

	/* do ldap search */
	if (ldap_api.ldap_params_search(&ld_result_count,
                                        h350_ldap_session.s,
                                        h350_base_dn.s,
                                        h350_search_scope_int,
                                        NULL,
                                        H350_AUTH_FILTER_PATTERN,
                                        digest_username_escaped.s)
            != 0)
        {
                LM_ERR("LDAP search failed\n");
		return E_H350_INTERNAL;
        }

	if (ld_result_count < 1)
	{
		LM_INFO("no H.350 entry found for username [%s]\n",
			digest_username_escaped.s);
		return E_H350_NO_SUCCESS;
	}
	if (ld_result_count > 1)
	{
		LM_WARN("more than one [%d] H.350 entry found for username [%s]\n",
			ld_result_count,
			digest_username_escaped.s);
	}

	/* get ldap result values */
	rc = ldap_api.ldap_result_attr_vals(&h350_sip_pwd_name, &attr_vals);
	if (rc < 0)
	{
                LM_ERR("getting LDAP attribute values failed\n");
                ldap_api.ldap_value_free_len(attr_vals);
		return E_H350_INTERNAL;
        }
        if ((rc > 0) || (attr_vals == NULL))
	{
                LM_INFO("no values found in LDAP entry for username [%s]\n",
			digest_username_escaped.s);
		ldap_api.ldap_value_free_len(attr_vals);
		return E_H350_INTERNAL;
        }

	digest_password.s = attr_vals[0]->bv_val;
        digest_password.len = attr_vals[0]->bv_len;

	/*
	 * write AVPs
	 */

	avp_val.s = digest_username;
	if (add_avp(	username_avp_type | AVP_VAL_STR,
			username_avp_name,
			avp_val)
		< 0)
	{
		LM_ERR("failed to create new AVP\n");
		ldap_api.ldap_value_free_len(attr_vals);
		return E_H350_INTERNAL;
	}

	avp_val.s = digest_password;
	if (add_avp(    password_avp_type | AVP_VAL_STR,
                        password_avp_name,
                        avp_val)
                < 0)
        {
                LM_ERR("failed to create new AVP\n");
                ldap_api.ldap_value_free_len(attr_vals);
                return E_H350_INTERNAL;
        }

	ldap_api.ldap_value_free_len(attr_vals);
	return E_H350_SUCCESS;
}
Beispiel #24
0
/* returns -1 on error, 0 on success */
int init_nonce_count()
{
	unsigned long size;
	unsigned long max_mem;
	unsigned orig_array_size;


	if (nid_crt==0){
		BUG("auth: init_nonce_count: nonce index must be "
				"initialized first (see init_nonce_id())\n");
		return -1;
	}
	orig_array_size=nc_array_size;
	if (nc_array_k==0){
		if (nc_array_size==0){
			nc_array_size=DEFAULT_NC_ARRAY_SIZE;
		}
		nc_array_k=bit_scan_reverse32(nc_array_size);
	}
	size=1UL<<nc_array_k; /* ROUNDDOWN to 2^nc_array_k */
	if (size < MIN_NC_ARRAY_SIZE){
		LM_WARN("nonce-count in.flight nonces is very low (%d),"
				" consider increasing nc_array_size to at least %d\n",
				orig_array_size, MIN_NC_ARRAY_SIZE);
	}
	if (size > MAX_NC_ARRAY_SIZE){
		LM_WARN("nonce-count in flight nonces is too high (%d),"
				" consider decreasing nc_array_size to at least %d\n",
				orig_array_size, MAX_NC_ARRAY_SIZE);
	}
	if (size!=nc_array_size){
		if (orig_array_size!=0)
			LM_INFO("nc_array_size rounded down to %ld\n", size);
		else
			LM_INFO("nc_array_size set to %ld\n", size);
	}
	max_mem=shm_available();
	if (size*sizeof(nc_t) >= max_mem){
		LM_ERR("nc_array_size (%ld) is too big for the configured "
				"amount of shared memory (%ld bytes <= %ld bytes)\n",
				size, max_mem, size*sizeof(nc_t));
		return -1;
	}else if (size*sizeof(nc_t) >= max_mem/2){
		LM_WARN("the currently configured nc_array_size (%ld)  "
				"would use more then 50%% of the available shared"
				" memory(%ld bytes)\n", size, max_mem);
	}
	nc_array_size=size;

	if (nid_pool_no>=nc_array_size){
		LM_ERR("nid_pool_no (%d) too high for the configured "
				"nc_array_size (%d)\n", nid_pool_no, nc_array_size);
		return -1;
	}
	nc_partition_size=nc_array_size >> nid_pool_k;
	nc_partition_k=nc_array_k-nid_pool_k;
	nc_partition_mask=(1<<nc_partition_k)-1;
	assert(nc_partition_size == nc_array_size/nid_pool_no);
	assert(1<<(nc_partition_k+nid_pool_k) == nc_array_size);

	if ((nid_t)nc_partition_size >= ((nid_t)(-1)/NID_INC)){
		LM_ERR("nc_array_size too big, try decreasing it or increasing"
				"the number of pools/partitions\n");
		return -1;
	}
	if (nc_partition_size  < MIN_NC_ARRAY_PARTITION){
		LM_WARN("nonce-count in-flight nonces very low,"
				" consider either decreasing nc_pool_no (%d) or "
				" increasing nc_array_size (%d) such that "
				"nc_array_size/nid_pool_no >= %d\n",
				nid_pool_no, orig_array_size, MIN_NC_ARRAY_PARTITION);
	}

	/*  array size should be multiple of sizeof(unsigned int) since we
	 *  access it as an uint array */
	nc_array=shm_malloc(sizeof(nc_t)*ROUND_INT(nc_array_size));
	if (nc_array==0){
		LM_ERR("init_nonce_count: memory allocation failure, consider"
				" either decreasing nc_array_size of increasing the"
				" the shared memory amount\n");
		goto error;
	}
	/* int the nc_array with the max nc value to avoid replay attacks after
	 * ser restarts (because the nc is already maxed out => no received
	 * nc will be accepted, until the corresponding cell is reset) */
	memset(nc_array, 0xff, sizeof(nc_t)*ROUND_INT(nc_array_size));
	return 0;
error:
	destroy_nonce_count();
	return -1;
}
Beispiel #25
0
static int mod_init(void)
{
	LM_INFO("initializing TCP-plain protocol\n");

	return 0;
}
Beispiel #26
0
/*
 * Wrapper around SSL_accept, returns -1 on error, 0 on success
 */
static int tls_accept(struct tcp_connection *c, short *poll_events)
{
	int ret, err;
	SSL *ssl;
	X509* cert;

	if ( (c->proto_flags&F_TLS_DO_ACCEPT)==0 ) {
		LM_BUG("invalid connection state (bug in TLS code)\n");
		return -1;
	}

	ssl = (SSL *) c->extra_data;
#ifndef OPENSSL_NO_KRB5
	if ( ssl->kssl_ctx==NULL )
		ssl->kssl_ctx = kssl_ctx_new( );
#endif
	ret = SSL_accept(ssl);
#ifndef OPENSSL_NO_KRB5
	if ( ssl->kssl_ctx ) {
		kssl_ctx_free( ssl->kssl_ctx );
		ssl->kssl_ctx = 0;
	}
#endif
	if (ret > 0) {
		LM_INFO("New TLS connection from %s:%d accepted\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
		/* TLS accept done, reset the flag */
		c->proto_flags &= ~F_TLS_DO_ACCEPT;

		LM_DBG("new TLS connection from %s:%d using %s %s %d\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port,
			SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl),
			SSL_get_cipher_bits(ssl, 0) );
		LM_DBG("local socket: %s:%d\n",
			ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port );
		cert = SSL_get_peer_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_accept: client TLS certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LM_WARN("TLS client certificate verification failed\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			LM_INFO("Client did not present a TLS certificate\n");
		}
		cert = SSL_get_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_accept: local TLS server certificate",
				cert);
		} else {
			/* this should not happen, servers always present a cert */
			LM_ERR("local TLS server domain has no certificate\n");
		}
		return 0;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
			case SSL_ERROR_ZERO_RETURN:
				LM_INFO("TLS connection from %s:%d accept failed cleanly\n",
					ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				c->state = S_CONN_BAD;
				return -1;
			case SSL_ERROR_WANT_READ:
				if (poll_events)
					*poll_events = POLLIN;
				return 0;
			case SSL_ERROR_WANT_WRITE:
				if (poll_events)
					*poll_events = POLLOUT;
				return 0;
			default:
				c->state = S_CONN_BAD;
				if (errno == 0) {
					LM_ERR("New TLS connection from %s:%d failed to accept:"
						" rejected by client\n",
						ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				} else {
					LM_ERR("New TLS connection from %s:%d failed to accept\n",
						ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
					LM_ERR("TLS error: (ret=%d, err=%d, errno=%d/%s):\n",
						ret, err, errno, strerror(errno));
					tls_print_errstack();
				}
				return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
/**
 * init module function
 */
static int mod_init(void)
{
#ifdef HAVE_IHTTP
	load_ih_f load_ih;
#endif
	int  i;
	init_db_url( db_url , 0 /*cannot be null*/);

	LM_INFO("initializing ...\n");
	if(!jdomain)
	{
		LM_ERR("jdomain is NULL\n");
		return -1;
	}

	/* import mysql functions */
	if (db_bind_mod(&db_url, &jabber_dbf)<0)
	{
		LM_ERR("database module not found\n");
		return -1;
	}

	if (!DB_CAPABILITY(jabber_dbf, DB_CAP_QUERY)) {
		LM_ERR("database module does not implement 'query' function\n");
		return -1;
	}

	db_con = (db_con_t**)shm_malloc(nrw*sizeof(db_con_t*));
	if (db_con == NULL)
	{
		LM_ERR("no more shm memory\n");
		return -1;
	}

	/* load the TM API */
	if (load_tm_api(&tmb)!=0) {
		LM_ERR("can't load TM API\n");
		return -1;
	}

#ifdef HAVE_IHTTP
	/* import the iHTTP auto-loading function */
	if ( !(load_ih=(load_ih_f)find_export("load_ih", IH_NO_SCRIPT_F, 0))) {
		LM_ERR("can't import load_ih\n");
		return -1;
	}
	/* let the auto-loading function load all TM stuff */
	if (load_ih( &ihb )==-1)
		return -1;
#endif
	
	pipes = (int**)pkg_malloc(nrw*sizeof(int*));
	if (pipes == NULL)
	{
		LM_ERR("no more pkg memory (pipes)\n");
		return -1;
	}
	
	for(i=0; i<nrw; i++)
	{
		pipes[i] = (int*)pkg_malloc(2*sizeof(int));
		if (!pipes[i])
		{
			LM_ERR("no more pkg memory (pipes)\n");
			return -1;
		}
	}
	
	for(i=0; i<nrw; i++)
	{	
		db_con[i] = jabber_dbf.init(&db_url);
		if (!db_con[i])
		{
			LM_ERR("failed to connect to the database\n");
			return -1;
		}
		else
		{
			if (jabber_dbf.use_table(db_con[i], &db_table) < 0) {
				LM_ERR("use_table failed\n");
				return -1;
			}
			LM_DBG("database connection opened successfully\n");
		}
	}

	
	/** creating the pipes */
	
	for(i=0;i<nrw;i++)
	{
		/* create the pipe*/
		if (pipe(pipes[i])==-1) {
			LM_ERR("cannot create pipe!\n");
			return -1;
		}
		LM_DBG("pipe[%d] = <%d>-<%d>\n", i, pipes[i][0], pipes[i][1]);
	}
	
	if((jwl = xj_wlist_init(pipes,nrw,max_jobs,cache_time,sleep_time,
				delay_time)) == NULL)
	{
		LM_ERR("failed to initialize workers list\n");
		return -1;
	}
	
	if(xj_wlist_set_aliases(jwl, jaliases, jdomain, proxy) < 0)
	{
		LM_ERR("failed to set aliases and outbound proxy\n");
		return -1;
	}

	LM_DBG("initialized ...\n");	
	return 0;
}
Beispiel #28
0
/*
 * wrapper around SSL_connect, returns 0 on success, -1 on error
 */
static int tls_connect(struct tcp_connection *c, short *poll_events)
{
	int ret, err;
	SSL *ssl;
	X509* cert;

	if ( (c->proto_flags&F_TLS_DO_CONNECT)==0 ) {
		LM_BUG("invalid connection state (bug in TLS code)\n");
		return -1;
	}

	ssl = (SSL *) c->extra_data;

	ret = SSL_connect(ssl);
	if (ret > 0) {
		LM_INFO("New TLS connection to %s:%d established\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
		c->proto_flags &= ~F_TLS_DO_CONNECT;
		LM_DBG("new TLS connection to %s:%d using %s %s %d\n",
			ip_addr2a(&c->rcv.src_ip), c->rcv.src_port,
			SSL_get_cipher_version(ssl), SSL_get_cipher_name(ssl),
			SSL_get_cipher_bits(ssl, 0)
			);
		LM_DBG("sending socket: %s:%d \n",
			ip_addr2a(&c->rcv.dst_ip), c->rcv.dst_port
			);
		cert = SSL_get_peer_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_connect: server TLS certificate", cert);
			if (SSL_get_verify_result(ssl) != X509_V_OK) {
				LM_WARN("TLS server certificate verification failed\n");
				tls_dump_verification_failure(SSL_get_verify_result(ssl));
			}
			X509_free(cert);
		} else {
			/* this should not happen, servers always present a cert */
			LM_ERR("server did not present a TLS certificate\n");
		}
		cert = SSL_get_certificate(ssl);
		if (cert != 0) {
			tls_dump_cert_info("tls_connect: local TLS client certificate",
				cert);
		} else {
			LM_INFO("local TLS client domain does not have a certificate\n");
		}
		return 0;
	} else {
		err = SSL_get_error(ssl, ret);
		switch (err) {
			case SSL_ERROR_ZERO_RETURN:
				LM_INFO("New TLS connection to %s:%d failed cleanly\n",
					ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				c->state = S_CONN_BAD;
				return -1;
			case SSL_ERROR_WANT_READ:
				if (poll_events)
					*poll_events = POLLIN;
				return 0;
			case SSL_ERROR_WANT_WRITE:
				if (poll_events)
					*poll_events = POLLOUT;
				return 0;
			case SSL_ERROR_SYSCALL:
				LM_ERR("SSL_ERROR_SYSCALL err=%s(%d)\n",
					strerror(errno), errno);
			default:
				LM_ERR("New TLS connection to %s:%d failed\n",
					ip_addr2a(&c->rcv.src_ip), c->rcv.src_port);
				LM_ERR("TLS error: %d (ret=%d) err=%s(%d)\n",
					err,ret,strerror(errno), errno);
				c->state = S_CONN_BAD;
				tls_print_errstack();
				return -1;
		}
	}

	LM_BUG("bug\n");
	return -1;
}
Beispiel #29
0
/**
 * The function is called to create a handle to a db table.
 * 
 * On startup, we do not create any of the db handles.
 * Instead it is done on first-use (lazy-initialized) to only create handles to 
 * files (db) that we require.
 * 
 * There is one db file per kamailio table (eg. acc), and they should exist
 * in your DB_PATH (refer to kamctlrc) directory.
 *
 * This function does _not_ create the underlying binary db tables.
 * Creating the tables MUST be manually performed before 
 * kamailio startup by 'kamdbctl create'
 *
 * Function returns NULL on error, which will cause kamailio to exit.
 *
 */
table_p km_bdblib_create_table(database_p _db, str *_s)
{

	int rc,i,flags;
	DB *bdb = NULL;
	table_p tp = NULL;
	char tblname[MAX_TABLENAME_SIZE]; 

	if(!_db || !_db->dbenv)
	{
		LM_ERR("no database_p or dbenv.\n");
		return NULL;
	}

	tp = (table_p)pkg_malloc(sizeof(table_t));
	if(!tp)
	{
		LM_ERR("no private memory for table_t.\n");
		return NULL;
	}

	if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0)
	{ 
		_db->dbenv->err(_db->dbenv, rc, "database create");
		LM_ERR("error in db_create, bdb error: %s.\n",db_strerror(rc));
		pkg_free(tp);
		return NULL;
	}

	memset(tblname, 0, MAX_TABLENAME_SIZE);
	strncpy(tblname, _s->s, _s->len);

#ifdef BDB_EXTRA_DEBUG
	LM_DBG("CREATE TABLE = %s\n", tblname);
#endif

	flags = DB_THREAD;

	if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0)
	{ 
		_db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname);
		LM_ERR("bdb open failed: %s.\n",db_strerror(rc));
		pkg_free(tp);
		return NULL;
	}

	if(!lock_init(&tp->sem))
	{
		goto error;
	}
	
	tp->name.s = (char*)pkg_malloc(_s->len*sizeof(char));
	memcpy(tp->name.s, _s->s, _s->len);
	tp->name.len = _s->len;
	tp->db=bdb;
	tp->ncols=0;
	tp->nkeys=0;
	tp->ro=0;    /*0=ReadWrite ; 1=ReadOnly*/
	tp->ino=0;   /*inode*/
	tp->logflags=0; /*bitmap; 4=Delete, 2=Update, 1=Insert, 0=None*/
	tp->fp=0;
	tp->t=0;
	
	for(i=0;i<MAX_NUM_COLS;i++)
		tp->colp[i] = NULL;

	/*load metadata; seeded\db_loaded when database are created*/
	
	/*initialize columns with metadata*/
	rc = km_load_metadata_columns(tp);
	if(rc!=0)
	{
		LM_ERR("FAILED to load METADATA COLS in table: %s.\n", tblname);
		goto error;
	}
	
	/*initialize columns default values from metadata*/
	rc = km_load_metadata_defaults(tp);
	if(rc!=0)
	{
		LM_ERR("FAILED to load METADATA DEFAULTS in table: %s.\n", tblname);
		goto error;
	}
	
	rc = km_load_metadata_keys(tp);
	if(rc!=0)
	{
		LM_ERR("FAILED to load METADATA KEYS in table: %s.\n", tblname);
		/*will have problems later figuring column types*/
		goto error;
	}

	/*opened RW by default; Query to set the RO flag */
	rc = km_load_metadata_readonly(tp);
	if(rc!=0)
	{
		LM_INFO("No METADATA_READONLY in table: %s.\n", tblname);
		/*non-critical; table will default to READWRITE*/
	}

	if(tp->ro)
	{	
		/*schema defines this table RO readonly*/
#ifdef BDB_EXTRA_DEBUG
		LM_DBG("TABLE %.*s is changing to READONLY mode\n"
			, tp->name.len, tp->name.s);
#endif
		
		if ((rc = bdb->close(bdb,0)) != 0)
		{ 
			_db->dbenv->err(_db->dbenv, rc, "DB->close: %s", tblname);
			LM_ERR("bdb close: %s.\n",db_strerror(rc));
			goto error;
		}
		
		bdb = NULL;
		if ((rc = db_create(&bdb, _db->dbenv, 0)) != 0)
		{ 
			_db->dbenv->err(_db->dbenv, rc, "database create");
			LM_ERR("error in db_create.\n");
			goto error;
		}
		
		flags = DB_THREAD | DB_RDONLY;
		if ((rc = bdb->open(bdb, NULL, tblname, NULL, DB_HASH, flags, 0664)) != 0)
		{ 
			_db->dbenv->err(_db->dbenv, rc, "DB->open: %s", tblname);
			LM_ERR("bdb open: %s.\n",db_strerror(rc));
			goto error;
		}
		tp->db=bdb;
	}
	
	/* set the journaling flags; flags indicate which operations
	   need to be journalled. (e.g possible to only journal INSERT.)
	*/
	rc = km_load_metadata_logflags(tp);
	if(rc!=0)
		LM_INFO("No METADATA_LOGFLAGS in table: %s.\n", tblname);
	
	if ((tp->logflags & JLOG_FILE) == JLOG_FILE)
		km_bdblib_create_journal(tp);
	
	return tp;
	
error:
	if(tp) 
	{
		pkg_free(tp->name.s);
		pkg_free(tp);
	}
	return NULL;
}
Beispiel #30
0
/**
 * init module function
 */
static int mod_init(void)
{
	m_tree_t *pt = NULL;

	if(register_mi_mod(exports.name, mi_cmds)!=0)
	{
		LM_ERR("failed to register MI commands\n");
		return -1;
	}

	db_url.len = strlen(db_url.s);
	db_table.len = strlen(db_table.s);
	tname_column.len = strlen(tname_column.s);
	tprefix_column.len = strlen(tprefix_column.s);
	tvalue_column.len = strlen(tvalue_column.s);

	value_param.len = strlen(value_param.s);
	dstid_param.len = strlen(dstid_param.s);
	weight_param.len = strlen(weight_param.s);
	count_param.len = strlen(count_param.s);

	if(pv_parse_spec(&value_param, &pv_value)<00
			|| !(pv_is_w(&pv_value)))
	{
		LM_ERR("cannot parse value pv or is read only\n");
		return -1;
	}

	if(pv_parse_spec(&dstid_param, &pv_dstid)<0
			|| pv_dstid.type!=PVT_AVP)
	{
		LM_ERR("cannot parse dstid avp\n");
		return -1;
	}

	if(pv_parse_spec(&weight_param, &pv_weight)<0
			|| pv_weight.type!=PVT_AVP)
	{
		LM_ERR("cannot parse dstid avp\n");
		return -1;
	}

	if(pv_parse_spec(&count_param, &pv_count)<0
			|| !(pv_is_w(&pv_weight)))
	{
		LM_ERR("cannot parse count pv or is read-only\n");
		return -1;
	}

	if(mt_fetch_rows<=0)
		mt_fetch_rows = 1000;

	mt_char_list.len = strlen(mt_char_list.s);
	if(mt_char_list.len<=0)
	{
		LM_ERR("invalid prefix char list\n");
		return -1;
	}
	LM_INFO("mt_char_list=%s \n", mt_char_list.s);
	mt_char_table_init();

	/* binding to mysql module */
	if(db_bind_mod(&db_url, &mt_dbf))
	{
		LM_ERR("database module not found\n");
		return -1;
	}

	if (!DB_CAPABILITY(mt_dbf, DB_CAP_ALL))
	{
		LM_ERR("database module does not "
		    "implement all functions needed by the module\n");
		return -1;
	}

	/* open a connection with the database */
	db_con = mt_dbf.init(&db_url);
	if(db_con==NULL)
	{
		LM_ERR("failed to connect to the database\n");        
		return -1;
	}
	
	LM_DBG("database connection opened successfully\n");
	
	if ( (mt_lock=lock_alloc())==0) {
		LM_CRIT("failed to alloc lock\n");
		goto error1;
	}
	if (lock_init(mt_lock)==0 ) {
		LM_CRIT("failed to init lock\n");
		goto error1;
	}
	
	if(mt_defined_trees())
	{
		LM_DBG("static trees defined\n");

		pt = mt_get_first_tree();

		while(pt!=NULL)
		{
			/* loading all information from database */
			if(mt_load_db(&pt->tname)!=0)
			{
				LM_ERR("cannot load info from database\n");
				goto error1;
			}
			pt = pt->next;
		}
	} else {
		if(db_table.len<=0)
		{
			LM_ERR("no trees table defined\n");
			goto error1;
		}
		if(mt_init_list_head()<0)
		{
			LM_ERR("unable to init trees list head\n");
			goto error1;
		}
		/* loading all information from database */
		if(mt_load_db_trees()!=0)
		{
			LM_ERR("cannot load trees from database\n");
			goto error1;
		}
	}
	mt_dbf.close(db_con);
	db_con = 0;

#if 0
	mt_print_tree(mt_get_first_tree());
#endif

	/* success code */
	return 0;

error1:
	if (mt_lock)
	{
		lock_destroy( mt_lock );
		lock_dealloc( mt_lock );
		mt_lock = 0;
	}
	mt_destroy_trees();

	if(db_con!=NULL)
		mt_dbf.close(db_con);
	db_con = 0;
	return -1;
}