void b2bl_clean(unsigned int ticks, void* param) { int i; b2bl_tuple_t* tuple, *tuple_next; unsigned int now; str bye = {BYE, BYE_LEN}; b2b_req_data_t req_data; now = get_ticks(); for(i = 0; i< b2bl_hsize; i++) { lock_get(&b2bl_htable[i].lock); tuple = b2bl_htable[i].first; while(tuple) { tuple_next = tuple->next; if(tuple->lifetime > 0 && tuple->lifetime < now) { LM_INFO("Found expired tuple [%.*s]: delete and send BYEs\n", tuple->key->len, tuple->key->s); if(tuple->bridge_entities[0] && tuple->bridge_entities[1] && !tuple->to_del) { if(!tuple->bridge_entities[0]->disconnected) { memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(tuple->bridge_entities[0]); req_data.method =&bye; b2b_api.send_request(&req_data); } if(!tuple->bridge_entities[1]->disconnected) { memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(tuple->bridge_entities[1]); req_data.method =&bye; b2b_api.send_request(&req_data); } } b2bl_delete(tuple, i, 0); } tuple = tuple_next; } lock_release(&b2bl_htable[i].lock); } }
/* * arguments: b2bl_key, new_dest, entity (1 - client) * */ static struct mi_root* mi_b2b_bridge(struct mi_root* cmd, void* param) { struct mi_node* node= NULL; str key; b2bl_tuple_t* tuple; str new_dest; str prov_media; unsigned int entity_no = 0; b2bl_entity_id_t* entity, *old_entity, *bridging_entity, *prov_entity = 0; struct sip_uri uri; str meth_inv = {INVITE, INVITE_LEN}; str meth_bye = {BYE, BYE_LEN}; unsigned int hash_index, local_index; str ok= str_init("ok"); b2b_req_data_t req_data; b2b_rpl_data_t rpl_data; node = cmd->node.kids; if(node == NULL) return 0; /* b2bl_key */ key = node->value; if(key.s == NULL || key.len== 0) { LM_ERR("Wrong b2b_logic key parameter\n"); return init_mi_tree(404, "Empty b2bl key", 14); } /* new destination- must be a valid SIP URI */ node = node->next; if(node == NULL) return 0; new_dest = node->value; if(new_dest.s == NULL || new_dest.len == 0) { LM_ERR("Empty new dest parameter\n"); return init_mi_tree(404, "Empty parameter", 15); } if(parse_uri(new_dest.s, new_dest.len, &uri)< 0) { LM_ERR("Bad argument. Not a valid uri [%.*s]\n", new_dest.len, new_dest.s); return init_mi_tree(404, "Bad parameter", 13); } /* the last parameter is optional, if present and 1 - > * means that destination from the current call must be * bridged to the new destination */ node = node->next; if(node) { if (node->value.len==1) { if(strncmp(node->value.s, "0", 1)==0) entity_no = 0; else if(strncmp(node->value.s, "1", 1)==0) entity_no = 1; else return init_mi_tree(404, "Invalid entity no parameter", 27); } else { return init_mi_tree(404, "Invalid entity no parameter", 27); } node = node->next; if (node) { /* parse new uri */ prov_media = node->value; if(parse_uri(node->value.s, node->value.len, &uri)< 0) { LM_ERR("Bad argument. Not a valid provisional media uri [%.*s]\n", new_dest.len, new_dest.s); return init_mi_tree(404, "Bad parameter", 13); } prov_entity = b2bl_create_new_entity(B2B_CLIENT, 0, &prov_media, 0, 0, 0, 0); if (!prov_entity) { LM_ERR("Failed to create new b2b entity\n"); goto free; } if (node->next) return init_mi_tree(404, MI_SSTR(MI_MISSING_PARM)); } } if(b2bl_parse_key(&key, &hash_index, &local_index) < 0) { LM_ERR("Failed to parse key '%.*s'\n", key.len, key.s); goto free; } entity = b2bl_create_new_entity(B2B_CLIENT, 0, &new_dest, 0, 0, 0, 0); if(entity == NULL) { LM_ERR("Failed to create new b2b entity\n"); goto free; } lock_get(&b2bl_htable[hash_index].lock); tuple = b2bl_search_tuple_safe(hash_index, local_index); if(tuple == NULL) { LM_ERR("No entity found\n"); goto error; } bridging_entity = tuple->bridge_entities[entity_no]; old_entity = tuple->bridge_entities[(entity_no?0:1)]; if(old_entity == NULL || bridging_entity == NULL) { LM_ERR("Wrong dialog id\n"); goto error; } if(old_entity->next || old_entity->prev) { LM_ERR("Can not disconnect entity [%p]\n", old_entity); b2bl_print_tuple(tuple, L_ERR); goto error; } /* send BYE to old client */ if(old_entity->disconnected) { memset(&rpl_data, 0, sizeof(b2b_rpl_data_t)); PREP_RPL_DATA(old_entity); rpl_data.method =METHOD_BYE; rpl_data.code =200; rpl_data.text =&ok; b2b_api.send_reply(&rpl_data); } else { old_entity->disconnected = 1; memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(old_entity); req_data.method =&meth_bye; b2b_api.send_request(&req_data); } if (0 == b2bl_drop_entity(old_entity, tuple)) { LM_ERR("Inconsistent tuple [%p]\n", tuple); b2bl_print_tuple(tuple, L_ERR); goto error; } if (old_entity->peer->peer == old_entity) old_entity->peer->peer = NULL; else { LM_ERR("Unexpected chain: old_entity=[%p] and old_entity->peer->peer=[%p]\n", old_entity, old_entity->peer->peer); goto error; } old_entity->peer = NULL; tuple->bridge_entities[0]= bridging_entity; if (prov_entity) { tuple->bridge_entities[1]= prov_entity; tuple->bridge_entities[2]= entity; /* we don't have to free it anymore */ prov_entity = 0; } else { tuple->bridge_entities[1]= entity; bridging_entity->peer = entity; entity->peer = bridging_entity; } tuple->scenario_state = B2B_BRIDGING_STATE; bridging_entity->state = 0; memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(bridging_entity); req_data.method =&meth_inv; b2b_api.send_request(&req_data); lock_release(&b2bl_htable[hash_index].lock); return init_mi_tree(200, "OK", 2); error: if(tuple) b2b_mark_todel(tuple); lock_release(&b2bl_htable[hash_index].lock); free: if (prov_entity) shm_free(prov_entity); return 0; }
static mi_response_t *mi_b2b_bridge(const mi_params_t *params, int entity_no, str *prov_media) { str key; b2bl_tuple_t* tuple; str new_dest; b2bl_entity_id_t* entity, *old_entity, *bridging_entity, *prov_entity = 0; struct sip_uri uri; str meth_inv = {INVITE, INVITE_LEN}; str meth_bye = {BYE, BYE_LEN}; unsigned int hash_index, local_index; str ok= str_init("ok"); b2b_req_data_t req_data; b2b_rpl_data_t rpl_data; int ret; if (get_mi_string_param(params, "dialog_id", &key.s, &key.len) < 0) return init_mi_param_error(); if (get_mi_string_param(params, "new_uri", &new_dest.s, &new_dest.len) < 0) return init_mi_param_error(); if(parse_uri(new_dest.s, new_dest.len, &uri)< 0) { LM_ERR("Bad argument. Not a valid uri [%.*s]\n", new_dest.len, new_dest.s); return init_mi_error(404, MI_SSTR("Invalid uri for the new destination")); } /* if 'flag' parameter is 1 - > * means that destination from the current call must be * bridged to the new destination */ if (entity_no != 0 && entity_no != 1) return init_mi_error(404, MI_SSTR("Invalid 'flag' parameter")); if (prov_media) { /* parse new uri */ if(parse_uri(prov_media->s, prov_media->len, &uri)< 0) { LM_ERR("Bad argument. Not a valid provisional media uri [%.*s]\n", new_dest.len, new_dest.s); return init_mi_error(404, MI_SSTR("Bad 'prov_media_uri' parameter")); } prov_entity = b2bl_create_new_entity(B2B_CLIENT, 0, prov_media, 0, 0, 0, 0, 0); if (!prov_entity) { LM_ERR("Failed to create new b2b entity\n"); goto free; } } ret = b2bl_get_tuple_key(&key, &hash_index, &local_index); if(ret < 0) { if (ret == -1) LM_ERR("Failed to parse key or find an entity [%.*s]\n", key.len, key.s); else LM_ERR("Could not find entity [%.*s]\n", key.len, key.s); goto free; } entity = b2bl_create_new_entity(B2B_CLIENT, 0, &new_dest, 0, 0, 0, 0, 0); if(entity == NULL) { LM_ERR("Failed to create new b2b entity\n"); goto free; } lock_get(&b2bl_htable[hash_index].lock); tuple = b2bl_search_tuple_safe(hash_index, local_index); if(tuple == NULL) { LM_ERR("No entity found\n"); goto error; } if (!tuple->bridge_entities[entity_no] || tuple->bridge_entities[entity_no]->disconnected) { LM_ERR("Can not bridge requested entity [%p]\n", tuple->bridge_entities[entity_no]); goto error; } bridging_entity = tuple->bridge_entities[entity_no]; old_entity = tuple->bridge_entities[(entity_no?0:1)]; if(old_entity == NULL || bridging_entity == NULL) { LM_ERR("Wrong dialog id\n"); goto error; } if(old_entity->next || old_entity->prev) { LM_ERR("Can not disconnect entity [%p]\n", old_entity); b2bl_print_tuple(tuple, L_ERR); goto error; } if(bridging_entity->state != B2BL_ENT_CONFIRMED) { LM_ERR("Wrong state for entity ek= [%.*s], tk=[%.*s]\n", bridging_entity->key.len,bridging_entity->key.s, tuple->key->len, tuple->key->s); goto error; } b2bl_print_tuple(tuple, L_DBG); /* send BYE to old client */ if(old_entity->disconnected) { memset(&rpl_data, 0, sizeof(b2b_rpl_data_t)); PREP_RPL_DATA(old_entity); rpl_data.method =METHOD_BYE; rpl_data.code =200; rpl_data.text =&ok; b2b_api.send_reply(&rpl_data); } else { old_entity->disconnected = 1; memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(old_entity); req_data.method =&meth_bye; b2b_api.send_request(&req_data); } if (0 == b2bl_drop_entity(old_entity, tuple)) { LM_ERR("Inconsistent tuple [%p]\n", tuple); b2bl_print_tuple(tuple, L_ERR); goto error; } if (old_entity->peer->peer == old_entity) old_entity->peer->peer = NULL; else { LM_ERR("Unexpected chain: old_entity=[%p] and old_entity->peer->peer=[%p]\n", old_entity, old_entity->peer->peer); goto error; } old_entity->peer = NULL; tuple->bridge_entities[0]= bridging_entity; if (prov_entity) { tuple->bridge_entities[1]= prov_entity; tuple->bridge_entities[2]= entity; /* we don't have to free it anymore */ prov_entity = 0; } else { tuple->bridge_entities[1]= entity; bridging_entity->peer = entity; entity->peer = bridging_entity; } tuple->scenario_state = B2B_BRIDGING_STATE; bridging_entity->state = 0; bridging_entity->sdp_type = B2BL_SDP_LATE; memset(&req_data, 0, sizeof(b2b_req_data_t)); PREP_REQ_DATA(bridging_entity); req_data.method =&meth_inv; b2b_api.send_request(&req_data); lock_release(&b2bl_htable[hash_index].lock); return init_mi_result_ok(); error: if(tuple) b2b_mark_todel(tuple); lock_release(&b2bl_htable[hash_index].lock); free: if (prov_entity) shm_free(prov_entity); return 0; }