int set_call_leg( struct sip_msg *msg, struct cc_call *call, str *new_leg) { str* id; LM_DBG("call %p moving to %.*s , state %d\n", call, new_leg->len, new_leg->s, call->state); if (call->b2bua_id.len==0) { /* b2b instance not initialized yet => * create new b2bua instance */ call->ref_cnt++; id = b2b_api.init( msg, &b2b_scenario, &new_leg, b2bl_callback_customer, (void*)call, B2B_DESTROY_CB|B2B_REJECT_CB|B2B_BYE_CB, NULL /* custom_hdrs */ ); if (id==NULL || id->len==0 || id->s==NULL) { LM_ERR("failed to init new b2bua call (empty ID received)\n"); return -2; } call->b2bua_id.s = (char*)shm_malloc(id->len); if (call->b2bua_id.s==NULL) { LM_ERR("failed to allocate b2bua ID\n"); return -1; } memcpy( call->b2bua_id.s, id->s, id->len); /* this must be the last, as we use it as marker for checking * if b2b entity is initialized */ call->b2bua_id.len = id->len; } else { /* call already ongoing */ if(b2b_api.bridge( &call->b2bua_id, new_leg, &call->caller_dn, 0) < 0) { LM_ERR("bridging failed\n"); b2b_api.terminate_call(&call->b2bua_id); return -1; } } /* remember last time when the call started */ call->last_start = get_ticks(); //b2b_api.set_state(&call->b2bua_id, call->state); return 0; }
static int load_sca_info_from_db(void) { db_res_t * res = NULL; db_val_t * values; db_row_t * rows; int i, j, nr_rows; unsigned int valid_record; unsigned int n_result_cols = 0; unsigned int shared_line_col, watchers_col; unsigned int app_shared_entity_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_state_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_call_info_appearance_uri_col[MAX_APPEARANCE_INDEX]; unsigned int app_b2bl_key_col[MAX_APPEARANCE_INDEX]; db_key_t q_cols[SCA_TABLE_TOTAL_COL_NO]; str shared_line, watchers_csv; //str_lst_t *watchers; //unsigned int size, watcher_size, watchers_no; //unsigned int size; unsigned int hash_index; //char *p; b2b_sca_record_t *record; b2b_sca_call_t *call; unsigned int shared_entity, appearance_index, call_state; str call_info_uri, call_info_apperance_uri, b2bl_key; b2bl_cb_ctx_t *cb_params; if(use_sca_table()) return -1; q_cols[shared_line_col = n_result_cols++] = &shared_line_column; q_cols[watchers_col = n_result_cols++] = &watchers_column; for (i=0; i<MAX_APPEARANCE_INDEX; i++) { q_cols[app_shared_entity_col[i] = n_result_cols++] = &app_shared_entity_column[i]; q_cols[app_call_state_col[i] = n_result_cols++] = &app_call_state_column[i]; q_cols[app_call_info_uri_col[i] = n_result_cols++] = &app_call_info_uri_column[i]; q_cols[app_call_info_appearance_uri_col[i] = n_result_cols++] = &app_call_info_appearance_uri_column[i]; q_cols[app_b2bl_key_col[i] = n_result_cols++] = &app_b2bl_key_column[i]; } /* select the whole tabel and all the columns */ if (DB_CAPABILITY(sca_dbf, DB_CAP_FETCH)) { if(sca_dbf.query(sca_db_handle, 0, 0, 0, q_cols, 0, SCA_TABLE_TOTAL_COL_NO, 0, 0) < 0) { LM_ERR("Error while querying (fetch) database\n"); return -1; } if(sca_dbf.fetch_result(sca_db_handle, &res, SCA_FETCH_SIZE)<0){ LM_ERR("fetching rows failed\n"); return -1; } } else { if(sca_dbf.query(sca_db_handle, 0, 0, 0, q_cols, 0, SCA_TABLE_TOTAL_COL_NO, 0, &res) < 0) { LM_ERR("Error while querying database\n"); return -1; } } nr_rows = RES_ROW_N(res); do { LM_DBG("loading [%i] records from db\n", nr_rows); rows = RES_ROWS(res); /* for every row/record */ for(i=0; i<nr_rows; i++){ values = ROW_VALUES(rows + i); if (VAL_NULL(values+shared_line_col) || VAL_NULL(values+watchers_col)) { LM_ERR("columns [%.*s] or/and [%.*s] cannot be null -> skipping\n", shared_line_column.len, shared_line_column.s, watchers_column.len, watchers_column.s); continue; } shared_line.s = (char*)values[shared_line_col].val.string_val; shared_line.len = strlen(shared_line.s); watchers_csv.s = (char*)values[watchers_col].val.string_val; watchers_csv.len = strlen(watchers_csv.s); record = restore_record(&shared_line, &watchers_csv); if (record == NULL) goto error; hash_index = core_hash(&shared_line, NULL, b2b_sca_hsize); j = 0; while (j < MAX_APPEARANCE_INDEX) { if( VAL_NULL(values + app_shared_entity_col[j]) || VAL_NULL(values + app_call_state_col[j]) || VAL_NULL(values + app_call_info_uri_col[j]) || VAL_NULL(values + app_call_info_appearance_uri_col[j]) || VAL_NULL(values + app_b2bl_key_col[j]) ) { goto cont; } appearance_index = j + 1; /* 1 - get shared_entity */ shared_entity = values[app_shared_entity_col[j]].val.int_val; if (shared_entity!=0 && shared_entity!=1) { LM_ERR("Unexpected shared_entity [%d] " "for shared_line [%.*s]\n", shared_entity, shared_line.len, shared_line.s); goto cont; } /* 2 - get call_state */ call_state = values[app_call_state_col[j]].val.int_val; if (call_state == IDLE_STATE) { LM_DBG("empty call[%d]\n", appearance_index); goto cont; } if (call_state > MAX_INDEX_STATE) { LM_ERR("Unexpected call_state [%d] for shared_line [%.*s]\n", call_state, shared_line.len, shared_line.s); goto cont; } /* 3 - get call_info_uri */ call_info_uri.s = (char*)values[app_call_info_uri_col[j]].val.string_val; if (call_info_uri.s) call_info_uri.len = strlen(call_info_uri.s); else { LM_ERR("Missing call_info_uri for shared_line [%.*s][%d]\n", shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("call_info_uri=[%.*s]\n", call_info_uri.len, call_info_uri.s); /* 4 - get call_info_apperance_uri */ call_info_apperance_uri.s = (char*) values[app_call_info_appearance_uri_col[j]].val.string_val; if (call_info_apperance_uri.s) call_info_apperance_uri.len = strlen(call_info_apperance_uri.s); else { LM_ERR("Missing call_info_apperance_uri for " "shared_line [%.*s][%d]\n", shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("call_info_apperance_uri=[%.*s]\n", call_info_apperance_uri.len, call_info_apperance_uri.s); /* 5 - get b2bl_key */ b2bl_key.s = (char*)values[app_b2bl_key_col[j]].val.string_val; if (b2bl_key.s) { b2bl_key.len = strlen(b2bl_key.s); if (b2bl_key.len > B2BL_MAX_KEY_LEN) { LM_ERR("buffer overflow on b2bl_key [%.*s]" " for shared_line [%.*s][%d]\n", b2bl_key.len, b2bl_key.s, shared_line.len, shared_line.s, appearance_index); goto cont; } LM_DBG("b2bl_key=[%.*s]\n", b2bl_key.len, b2bl_key.s); } else { LM_ERR("Missing b2bl_key for shared_line [%.*s][1]\n", shared_line.len, shared_line.s); goto cont; } /* restore the call */ call = restore_call(record, appearance_index, shared_entity, call_state, &call_info_uri, &call_info_apperance_uri); if (call == NULL) { goto error; } /* update record */ if (0!=b2b_sca_update_call_record_key(call, &b2bl_key)) { LM_ERR("Unable to update b2bl_key [%.*s]\n", b2bl_key.len, b2bl_key.s); shm_free(call); call = NULL; record->call[appearance_index-1] = NULL; goto cont; } /* Prepare b2b_logic callback params. */ cb_params = build_cb_params(hash_index, &shared_line, appearance_index); if (cb_params == NULL) { LM_ERR("Unable to build cb_params\n"); goto error; } /* re-register callbacks */ if(b2bl_api.register_cb(&b2bl_key, &sca_logic_notify, cb_params, B2B_RE_INVITE_CB|B2B_CONFIRMED_CB|B2B_DESTROY_CB) != 0){ LM_ERR("Unable register b2b cb\n"); shm_free(call); call = NULL; record->call[appearance_index-1] = NULL; goto cont; } cont: j++; } valid_record = j = 0; while (j < MAX_APPEARANCE_INDEX) { if (record->call[j]) { valid_record = 1; goto check_valid_record; } j++; } check_valid_record: if (valid_record) { b2b_sca_print_record(record); insert_record(hash_index, record); } else { LM_DBG("removing the record from db!\n"); delete_sca_info_from_db(record); } LM_DBG("Done\n"); } /* any more data to be fetched ?*/ if (DB_CAPABILITY(sca_dbf, DB_CAP_FETCH)) { if (sca_dbf.fetch_result(sca_db_handle, &res, SCA_FETCH_SIZE)<0) { LM_ERR("fetching more rows failed\n"); goto error; } nr_rows = RES_ROW_N(res); } else { nr_rows = 0; } }while (nr_rows>0); sca_dbf.free_result(sca_db_handle, res); return 0; error: sca_dbf.free_result(sca_db_handle, res); return -1; }
int sca_bridge_request(struct sip_msg* msg, str* p1, str* p2) { pv_value_t pv_val; str shared_line = {NULL, 0}; str publish_hdr = {NULL, 0}; int method_value, ret; //int entity_no; unsigned int hash_index; b2b_sca_record_t *record = NULL; b2b_sca_call_t *call; unsigned int appearance; if (p1 && (pv_get_spec_value(msg, (pv_spec_t *)p1, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_STR) { LM_DBG("got shared_line:'%.*s'\n", pv_val.rs.len, pv_val.rs.s); shared_line = pv_val.rs; } else { LM_ERR("Unable to get shared_line from PV that is not a string\n"); return -1; } } else { LM_ERR("Unable to get shared_line from pv:%p\n", p1); return -1; } /* Get the hash index for the shared line. */ hash_index = core_hash(&shared_line, NULL, b2b_sca_hsize); LM_DBG("got hash_index=[%d] for shared line [%.*s]\n", hash_index, shared_line.len, shared_line.s); if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse message\n"); return -1; } method_value = msg->first_line.u.request.method_value; if (method_value != METHOD_INVITE) { LM_ERR("nonINVITE [%d] cannot bridge a call\n", method_value); return -1; } ret = tmb.t_newtran(msg); if(ret < 1) { if(ret == 0) { LM_DBG("It is a retransmission, drop\n"); tmb.unref_cell(tmb.t_gett()); } else { LM_ERR("Error when creating tm transaction\n"); } return 0; } if (!msg->call_info) { LM_ERR("No 'Call-Info' header\n"); return -1; } /* Extract required appearance from the received request */ appearance = get_app_index(msg); if (appearance==0) return -1; lock_get(&b2b_sca_htable[hash_index].lock); record = b2b_sca_search_record_safe(hash_index, &shared_line); if (record == NULL) { lock_release(&b2b_sca_htable[hash_index].lock); LM_ERR("record not found for shared line [%.*s] on hash index [%d]\n", shared_line.len, shared_line.s, hash_index); // FIXME: /* Build an empty PUBLISH header */ //if (build_publish_call_info_header(NULL, &publish_hdr) != 0) { // LM_ERR("Unable to build PUBLISH Call-Info header\n"); //} goto error; } b2b_sca_print_record(record); call = b2b_sca_search_call_safe(record, appearance); if (call == NULL) goto error; if (call->call_state != HELD_STATE) { LM_ERR("Improper call state [%d] for bridging\n", call->call_state); goto error; } /* What will happen if the b2b_logic entity doesn't exist anymore? */ LM_DBG("*** BRIDGING THE REQUEST to entity [%d] on tuple [%.*s]\n", call->shared_entity, call->b2bl_key.len, call->b2bl_key.s); ret = b2bl_api.bridge_msg(msg, &call->b2bl_key, call->shared_entity); if (ret != 0) { /* FIXME: * handle the error here */ LM_ERR("*** got ret [%d]\n", ret); goto error; } LM_DBG("*** got ret [%d]\n", ret); /* Set the state back to active */ call->call_state = ACTIVE_STATE; /* Reset the shared_entity */ call->shared_entity = 0; /* Prepare PUBLISH Call-Info header. */ if (build_publish_call_info_header(record, &publish_hdr) != 0) { lock_release(&b2b_sca_htable[hash_index].lock); LM_ERR("Unable to build PUBLISH Call-Info header\n"); return B2B_FOLLOW_SCENARIO_CB_RET; } /* Save the record to db. */ if (push_sca_info_to_db(record, appearance, 1) != 0) LM_ERR("db out of synch\n"); /* Notify the watchers. */ sca_publish(record, &publish_hdr); lock_release(&b2b_sca_htable[hash_index].lock); return 1; error: lock_release(&b2b_sca_htable[hash_index].lock); if (publish_hdr.s && publish_hdr.s != publish_call_info_hdr_buf) pkg_free(publish_hdr.s); return -1; }
int sca_init_request(struct sip_msg* msg, str* p1, str* p2) { int method_value, ret; //unsigned int size, hash_index, shared_entity; unsigned int hash_index, shared_entity, app_index; str *b2bl_key, *host, *port, *display, *uri, *shared_line; //char *p; //uri_type scheme; struct to_body *appearance_name_addr_body; pv_value_t pv_val; b2b_sca_record_t *record = NULL; b2b_sca_call_t *call = NULL; b2bl_cb_ctx_t *cb_params; str publish_hdr = {NULL, 0}; str custom_hdr = {NULL, 0}; str call_info_uri = {NULL, 0}; str call_info_apperance_uri = {NULL, 0}; if (parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("failed to parse message\n"); return -1; } method_value = msg->first_line.u.request.method_value; if (method_value != METHOD_INVITE) { LM_ERR("nonINVITE [%d] cannot initiate a call\n", method_value); return -1; } ret = tmb.t_newtran(msg); if(ret < 1) { if(ret == 0) { LM_DBG("It is a retransmission, drop\n"); tmb.unref_cell(tmb.t_gett()); } else { LM_ERR("Error when creating tm transaction\n"); } return 0; } if (p1 && (pv_get_spec_value(msg, (pv_spec_t *)p1, &pv_val) == 0)) { if (pv_val.flags & PV_VAL_INT) { shared_entity = pv_val.ri; LM_DBG("got shared_entity %d\n", shared_entity); } else if (pv_val.flags & PV_VAL_STR) { if(str2int(&(pv_val.rs), (unsigned int*)&shared_entity) != 0) { LM_ERR("Unable to get entity_no from pv '%.*s'\n", pv_val.rs.len, pv_val.rs.s); return -1; } } else { LM_ERR("shared entity not a str or int type\n"); return -1; } } else { LM_ERR("Unable to get shared entity from pv:%p\n", p1); return -1; } switch (shared_entity) { case 0: LM_DBG("Incoming call from shared line\n"); break; case 1: LM_DBG("Outgoing call via a shared line\n"); break; default: LM_ERR("shared line entity should be 0 or 1\n"); return -1; } /* Get the hash index for the shared line. */ if (get_hash_index_and_shared_line(msg, &hash_index, &shared_line)<0) return -1; LM_DBG("got hash_index=[%d] for shared line [%.*s]\n", hash_index, shared_line->len, shared_line->s); /* Get the appearance name-addr for this call. */ appearance_name_addr_body = get_appearance_name_addr(msg); if (appearance_name_addr_body == NULL) { LM_ERR("unable to get apperance of this call\n"); return -1; } //scheme = appearance_name_addr_body->parsed_uri.type; host = &appearance_name_addr_body->parsed_uri.host; port = &appearance_name_addr_body->parsed_uri.port; display = &appearance_name_addr_body->display; uri = &appearance_name_addr_body->uri; LM_DBG("display uri [%.*s][%.*s] from host:port [%.*s]:[%.*s]\n", display->len, display->s, uri->len, uri->s, host->len, host->s, port->len, port->s); /* Prepare absoluteURI for Call-Info header. */ if (build_absoluteURI(host, port, &call_info_uri) != 0) goto error1; /* Prepare appearanceURI param for Call-Info header. */ if (build_appearanceURI(display, uri, &call_info_apperance_uri) != 0) goto error1; /* Extract required appearance from the received request */ app_index = get_app_index(msg); /* Adding call to the sca_table. */ lock_get(&b2b_sca_htable[hash_index].lock); if (b2b_sca_add_call_record(hash_index, shared_line, shared_entity, app_index, &call_info_uri, &call_info_apperance_uri, &record, &call) != 0) { LM_ERR("unable to add record to sca htable\n"); goto error2; } /* Prepare INVITE Call-Info header. */ if (build_invite_call_info_header(call, &call_info_uri, &custom_hdr) != 0) goto error2; /* Prepare PUBLISH Call-Info header. */ if (build_publish_call_info_header(record, &publish_hdr) != 0) { LM_ERR("Unable to build PUBLISH Call-Info header\n"); goto error2; } /* Prepare b2b_logic callback params. */ cb_params = build_cb_params(hash_index, shared_line, call->appearance_index); if (cb_params == NULL) goto error2; LM_DBG("*** INITIALIZING \"top hiding\" SCENARIO with cb_params [%p]\n", cb_params); /* release the lock here to avoid deadlock while getting callback notifications */ lock_release(&b2b_sca_htable[hash_index].lock); b2bl_key = b2bl_api.init(msg, &scenario, NULL, &sca_logic_notify, (void *)cb_params, B2B_RE_INVITE_CB|B2B_CONFIRMED_CB|B2B_DESTROY_CB, &custom_hdr); lock_get(&b2b_sca_htable[hash_index].lock); if (!b2bl_key || !b2bl_key->s || !b2bl_key->len) goto error2; else if (b2b_sca_update_call_record_key(call, b2bl_key) != 0) goto error3; /* Save the record to db. */ if (push_sca_info_to_db(record, call->appearance_index, 0) != 0) goto error3; /* Notify the watchers. */ sca_publish(record, &publish_hdr); lock_release(&b2b_sca_htable[hash_index].lock); if (publish_hdr.s != publish_call_info_hdr_buf) pkg_free(publish_hdr.s); if (custom_hdr.s != invite_call_info_hdr_buf) pkg_free(custom_hdr.s); if (call_info_uri.s != call_info_uri_buf) pkg_free(call_info_uri.s); if (call_info_apperance_uri.s != call_info_apperance_uri_buf) pkg_free(call_info_apperance_uri.s); return 1; error3: /* Release the call */ b2bl_api.terminate_call(b2bl_key); error2: lock_release(&b2b_sca_htable[hash_index].lock); error1: if (publish_hdr.s != publish_call_info_hdr_buf) pkg_free(publish_hdr.s); if (custom_hdr.s != invite_call_info_hdr_buf) pkg_free(custom_hdr.s); if (call_info_uri.s != call_info_uri_buf) pkg_free(call_info_uri.s); if (call_info_apperance_uri.s != call_info_apperance_uri_buf) pkg_free(call_info_apperance_uri.s); return -1; }