/* 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; }
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; }
/* 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; }
/** * 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; }
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; } }
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; }
/** * 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; }
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); }
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; }
/*! \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; }
/** * 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; }
/* 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; }
/* 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; }
/** * 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; } } } }
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; }
/*! 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(¶ms, 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; }
/* 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; }
/** 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)*/ }
static int mod_init(void) { LM_INFO("initializing...\n"); suffix.len = strlen(suffix.s); return 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, ¶ms_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; }
/** * 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; }
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; }
/* 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; }
static int mod_init(void) { LM_INFO("initializing TCP-plain protocol\n"); return 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; }
/* * 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; }
/** * 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; }
/** * 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; }