int replicate_lb_status_update(bin_packet_t *packet, struct lb_data *data) { struct lb_dst *dst; unsigned int group, flags; str uri; bin_pop_int(packet, &group); bin_pop_str(packet, &uri); bin_pop_int(packet, &flags); for( dst=data->dsts; dst; dst=dst->next ) { if ( (dst->group == group) && (strncmp(dst->uri.s, uri.s, dst->uri.len) == 0)) { if ((dst->flags&LB_DST_STAT_MASK) != flags) { /* import the status flags */ dst->flags = ((~LB_DST_STAT_MASK)&dst->flags)| (LB_DST_STAT_MASK&flags); /* raise event of status change */ lb_raise_event(dst); return 0; } } } return -1; }
static int receive_ucontact_delete(bin_packet_t *packet) { udomain_t *domain; urecord_t *record; ucontact_t *contact; str d, aor, contact_str, callid; int cseq, rc; bin_pop_str(packet, &d); bin_pop_str(packet,&aor); bin_pop_str(packet,&contact_str); bin_pop_str(packet,&callid); bin_pop_int(packet,&cseq); if (find_domain(&d, &domain) != 0) { LM_ERR("domain '%.*s' is not local\n", d.len, d.s); goto error; } lock_udomain(domain, &aor); /* failure in retrieving a urecord may be ok, because packet order in UDP * is not guaranteed, so urecord_delete commands may arrive before * ucontact_delete's */ if (get_urecord(domain, &aor, &record) != 0) { LM_INFO("failed to fetch local urecord - ignoring request " "(ci: '%.*s')\n", callid.len, callid.s); unlock_udomain(domain, &aor); return 0; } /* simply specify a higher cseq and completely avoid any complications */ rc = get_ucontact(record, &contact_str, &callid, cseq + 1, &contact); if (rc != 0 && rc != 2) { LM_ERR("contact '%.*s' not found: (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } if (skip_replicated_db_ops) contact->flags |= FL_MEM; if (delete_ucontact(record, contact, 1) != 0) { LM_ERR("failed to delete ucontact '%.*s' (ci: '%.*s')\n", contact_str.len, contact_str.s, callid.len, callid.s); unlock_udomain(domain, &aor); goto error; } 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; }
void receive_dlg_binary_packet(int packet_type, struct receive_info *ri, void *att) { int rc; char *ip; unsigned short port; int server_id; rc = bin_pop_int(&server_id); if (rc < 0) return; LM_DBG("Received a binary packet!\n"); if(get_bin_pkg_version() != BIN_VERSION){ LM_ERR("incompatible bin protocol version\n"); return; } if (!accept_replicated_dlg) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("Unwanted dialog packet received from %s:%hu (type=%d)\n", ip, port, packet_type); return; } if(!clusterer_api.check(accept_replicated_dlg, &ri->src_su, server_id, ri->proto)) return; switch (packet_type) { case REPLICATION_DLG_CREATED: LM_DBG("AAAA dlg_replicated_create\n"); rc = dlg_replicated_create(NULL, NULL, NULL, 1); if_update_stat(dlg_enable_stats, create_recv, 1); break; case REPLICATION_DLG_UPDATED: LM_DBG("AAAA dlg_replicated_update\n"); rc = dlg_replicated_update(); if_update_stat(dlg_enable_stats, update_recv, 1); break; case REPLICATION_DLG_DELETED: LM_DBG("AAAA dlg_replicated_deleted\n"); rc = dlg_replicated_delete(); if_update_stat(dlg_enable_stats, delete_recv, 1); break; default: rc = -1; get_su_info(&ri->src_su.s, ip, port); LM_WARN("Invalid dialog binary packet command: %d (from %s:%hu)\n", packet_type, ip, port); } if (rc != 0) LM_ERR("Failed to process a binary packet!\n"); }
static int receive_sync_packet(bin_packet_t *packet) { int is_contact; int rc = -1; while (clusterer_api.sync_chunk_iter(packet)) { bin_pop_int(packet, &is_contact); if (is_contact) { if (receive_ucontact_insert(packet) == 0) rc = 0; } else if (receive_urecord_insert(packet) == 0) rc = 0; } return rc; }
static void bin_receive_packets(int packet_type, struct receive_info *ri, void *ptr) { struct module_list *module; unsigned short port; int machine_id; char *ip; int rc; rc = bin_pop_int(&machine_id); if (rc < 0) return; get_su_info(&ri->src_su.s, ip, port); LM_DBG("received bin packet from source: %s:%hu\n", ip, port); module = (struct module_list *) ptr; if (module->auth_check) { if (!clusterer_check(module->accept_cluster_id, &ri->src_su, machine_id, ri->proto)) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } } rc = set_in_timestamp(module, machine_id); if (rc < 0) { module->cb(SERVER_TEMP_DISABLED, ri, machine_id); return; } module->cb(packet_type, ri, machine_id); }
/** * replicates a confirmed dialog from another OpenSIPS instance * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_create(struct dlg_cell *cell, str *ftag, str *ttag, int safe) { int next_id, h_entry; unsigned int dir, dst_leg; str callid, from_uri, to_uri, from_tag, to_tag; str cseq1,cseq2,contact1,contact2,rroute1,rroute2,mangled_fu,mangled_tu; str sock, vars, profiles; struct dlg_cell *dlg = NULL; struct socket_info *caller_sock, *callee_sock; struct dlg_entry *d_entry; if_update_stat(dlg_enable_stats, processed_dlgs, 1); LM_DBG("Received replicated dialog!\n"); if (!cell) { bin_pop_str(&callid); bin_pop_str(&from_tag); bin_pop_str(&to_tag); bin_pop_str(&from_uri); bin_pop_str(&to_uri); dlg = get_dlg(&callid, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); if (dlg) { LM_DBG("Dialog with ci '%.*s' is already created\n", callid.len, callid.s); unref_dlg_unsafe(dlg, 1, d_entry); dlg_unlock(d_table, d_entry); return 0; } dlg = build_new_dlg(&callid, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto pre_linking_error; } } else { h_entry = dlg_hash(&cell->callid); d_entry = &d_table->entries[h_entry]; if (safe) dlg_lock(d_table, d_entry); from_tag = *ftag; to_tag = *ttag; dlg = cell; } bin_pop_int(&dlg->h_id); bin_pop_int(&dlg->start_ts); bin_pop_int(&dlg->state); next_id = d_table->entries[dlg->h_entry].next_id; d_table->entries[dlg->h_entry].next_id = (next_id <= dlg->h_id) ? (dlg->h_id + 1) : next_id; if (bin_pop_str(&sock)) goto pre_linking_error; caller_sock = fetch_socket_info(&sock); if (bin_pop_str(&sock)) goto pre_linking_error; callee_sock = fetch_socket_info(&sock); if (!caller_sock || !callee_sock) { LM_ERR("Dialog in DB doesn't match any listening sockets\n"); goto pre_linking_error; } bin_pop_str(&cseq1); bin_pop_str(&cseq2); bin_pop_str(&rroute1); bin_pop_str(&rroute2); bin_pop_str(&contact1); bin_pop_str(&contact2); bin_pop_str(&mangled_fu); bin_pop_str(&mangled_tu); /* add the 2 legs */ if (dlg_add_leg_info(dlg, &from_tag, &rroute1, &contact1, &cseq1, caller_sock, 0, 0) != 0 || dlg_add_leg_info(dlg, &to_tag, &rroute2, &contact2, &cseq2, callee_sock, &mangled_fu, &mangled_tu) != 0) { LM_ERR("dlg_set_leg_info failed\n"); goto pre_linking_error; } dlg->legs_no[DLG_LEG_200OK] = DLG_FIRST_CALLEE_LEG; /* link the dialog into the hash */ dlg->h_id = d_entry->next_id++; if (!d_entry->first) d_entry->first = d_entry->last = dlg; else { d_entry->last->next = dlg; dlg->prev = d_entry->last; d_entry->last = dlg; } dlg->ref++; d_entry->cnt++; bin_pop_str(&vars); bin_pop_str(&profiles); bin_pop_int(&dlg->user_flags); bin_pop_int(&dlg->flags); bin_pop_int((void *)&dlg->tl.timeout); bin_pop_int(&dlg->legs[DLG_CALLER_LEG].last_gen_cseq); bin_pop_int(&dlg->legs[callee_idx(dlg)].last_gen_cseq); if (dlg->tl.timeout <= (unsigned int)time(0)) dlg->tl.timeout = 0; else dlg->tl.timeout -= (unsigned int)time(0); /* restore the timer values */ if (insert_dlg_timer(&dlg->tl, (int)dlg->tl.timeout) != 0) { LM_CRIT("Unable to insert dlg %p [%u:%u] " "with clid '%.*s' and tags '%.*s' '%.*s'\n", dlg, dlg->h_entry, dlg->h_id, dlg->callid.len, dlg->callid.s, dlg->legs[DLG_CALLER_LEG].tag.len, dlg->legs[DLG_CALLER_LEG].tag.s, dlg->legs[callee_idx(dlg)].tag.len, ZSW(dlg->legs[callee_idx(dlg)].tag.s)); goto error; } if (dlg->state == DLG_STATE_CONFIRMED_NA || dlg->state == DLG_STATE_CONFIRMED) active_dlgs_cnt++; /* reference the dialog as kept in the timer list */ ref_dlg_unsafe(dlg, 1); LM_DBG("Received initial timeout of %d for dialog %.*s, safe = %d\n",dlg->tl.timeout,callid.len,callid.s,safe); dlg->lifetime = 0; /* Do not replicate the pinging - we might terminate dialogs badly when running as backup if (dlg->flags & DLG_FLAG_PING_CALLER || dlg->flags & DLG_FLAG_PING_CALLEE) { if (insert_ping_timer(dlg) != 0) LM_CRIT("Unable to insert dlg %p into ping timer\n",dlg); else { ref_dlg_unsafe(dlg, 1); } } */ if (dlg_db_mode == DB_MODE_DELAYED) { /* to be later removed by timer */ ref_dlg_unsafe(dlg, 1); } if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 0, 1); if_update_stat(dlg_enable_stats, active_dlgs, 1); run_load_callback_per_dlg(dlg); return 0; pre_linking_error: dlg_unlock(d_table, d_entry); if (dlg) destroy_dlg(dlg); return -1; error: dlg_unlock(d_table, d_entry); if (dlg) unref_dlg(dlg, 1); return -1; }
/** * replicates the remote update of an ongoing dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_update(void) { struct dlg_cell *dlg; str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles; unsigned int dir, dst_leg; int timeout, h_entry; str st; struct dlg_entry *d_entry; bin_pop_str(&call_id); bin_pop_str(&from_tag); bin_pop_str(&to_tag); bin_pop_str(&from_uri); bin_pop_str(&to_uri); LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n", call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s, from_uri.len, from_uri.s, to_uri.len, to_uri.s); dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&call_id); d_entry = &d_table->entries[h_entry]; dlg_lock(d_table, d_entry); if (!dlg) { /* TODO: change to LM_DBG */ LM_ERR("dialog not found, building new\n"); dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto error; } return dlg_replicated_create(dlg, &from_tag, &to_tag, 0); } bin_skip_int(2); bin_pop_int(&dlg->state); bin_skip_str(2); bin_pop_str(&st); if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) { LM_ERR("failed to update caller cseq\n"); goto error; } bin_pop_str(&st); if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) { LM_ERR("failed to update callee cseq\n"); goto error; } bin_skip_str(6); bin_pop_str(&vars); bin_pop_str(&profiles); bin_pop_int(&dlg->user_flags); bin_pop_int(&dlg->flags); bin_pop_int(&timeout); bin_skip_int(2); timeout -= time(0); LM_DBG("Received updated timeout of %d for dialog %.*s\n",timeout,call_id.len,call_id.s); if (dlg->lifetime != timeout) { dlg->lifetime = timeout; if (update_dlg_timer(&dlg->tl, dlg->lifetime) == -1) LM_ERR("failed to update dialog lifetime!\n"); } unref_dlg_unsafe(dlg, 1, d_entry); if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1); return 0; error: dlg_unlock(d_table, d_entry); return -1; }
/** * replicates the remote update of an ongoing dialog locally * by reading the relevant information using the Binary Packet Interface */ int dlg_replicated_update(bin_packet_t *packet) { struct dlg_cell *dlg; str call_id, from_tag, to_tag, from_uri, to_uri, vars, profiles; unsigned int dir, dst_leg; int timeout, h_entry; str st; struct dlg_entry *d_entry; int rcv_flags, save_new_flag; bin_pop_str(packet, &call_id); bin_pop_str(packet, &from_tag); bin_pop_str(packet, &to_tag); bin_pop_str(packet, &from_uri); bin_pop_str(packet, &to_uri); LM_DBG("replicated update for ['%.*s' '%.*s' '%.*s' '%.*s' '%.*s']\n", call_id.len, call_id.s, from_tag.len, from_tag.s, to_tag.len, to_tag.s, from_uri.len, from_uri.s, to_uri.len, to_uri.s); dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg); h_entry = dlg_hash(&call_id); d_entry = &d_table->entries[h_entry]; dlg_lock(d_table, d_entry); if (!dlg) { LM_DBG("dialog not found, building new\n"); dlg = build_new_dlg(&call_id, &from_uri, &to_uri, &from_tag); if (!dlg) { LM_ERR("Failed to create replicated dialog!\n"); goto error; } return dlg_replicated_create(packet ,dlg, &from_tag, &to_tag, 0); } bin_skip_int(packet, 2); bin_pop_int(packet, &dlg->state); bin_skip_str(packet, 2); bin_pop_str(packet, &st); if (dlg_update_cseq(dlg, DLG_CALLER_LEG, &st, 0) != 0) { LM_ERR("failed to update caller cseq\n"); goto error; } bin_pop_str(packet, &st); if (dlg_update_cseq(dlg, callee_idx(dlg), &st, 0) != 0) { LM_ERR("failed to update callee cseq\n"); goto error; } bin_skip_str(packet, 6); bin_pop_str(packet, &vars); bin_pop_str(packet, &profiles); bin_pop_int(packet, &dlg->user_flags); bin_pop_int(packet, &dlg->mod_flags); bin_pop_int(packet, &rcv_flags); /* make sure an update received immediately after a create can't * incorrectly erase the DLG_FLAG_NEW before locally writing to DB */ save_new_flag = dlg->flags & DLG_FLAG_NEW; dlg->flags = rcv_flags; dlg->flags |= ((save_new_flag ? DLG_FLAG_NEW : 0) | DLG_FLAG_CHANGED); bin_pop_int(packet, &timeout); bin_skip_int(packet, 2); timeout -= time(0); LM_DBG("Received updated timeout of %d for dialog %.*s\n", timeout, call_id.len, call_id.s); if (dlg->lifetime != timeout) { dlg->lifetime = timeout; switch (update_dlg_timer(&dlg->tl, dlg->lifetime) ) { case -1: LM_ERR("failed to update dialog lifetime!\n"); /* continue */ case 0: /* timeout value was updated */ break; case 1: /* dlg inserted in timer list with new expire (reference it)*/ ref_dlg(dlg,1); } } unref_dlg_unsafe(dlg, 1, d_entry); if (vars.s && vars.len != 0) read_dialog_vars(vars.s, vars.len, dlg); dlg->flags |= DLG_FLAG_VP_CHANGED; dlg_unlock(d_table, d_entry); if (profiles.s && profiles.len != 0) read_dialog_profiles(profiles.s, profiles.len, dlg, 1, 1); return 0; error: dlg_unlock(d_table, d_entry); return -1; }
void receive_prof_repl(bin_packet_t *packet) { time_t now; str name; str value; unsigned int counter; struct dlg_profile_table *profile; int has_value; int i; void **dst; prof_value_info_t *rp; repl_prof_count_t *destination; /* optimize profile search */ struct dlg_profile_table *old_profile = NULL; str old_name = {NULL,0}; if (!profile_repl_cluster) return; if (packet->type != REPLICATION_DLG_PROFILE) { LM_WARN("Invalid dialog binary packet command: %d (from node: %d in cluster: %d)\n", packet->type, packet->src_id, profile_repl_cluster); return; } now = time(0); //*repl_prof_dests[index].last_msg = now; for (;;) { if (bin_pop_str(packet ,&name) == 1) break; /* pop'ed all pipes */ /* check if the same profile was sent */ if (!old_profile || old_name.len != name.len || memcmp(name.s, old_name.s, name.len) != 0) { old_profile = get_dlg_profile(&name); if (!old_profile) LM_WARN("received unknown profile <%.*s> from node %d\n", name.len, name.s, packet->src_id); old_name = name; } profile = old_profile; if (bin_pop_int(packet, &has_value) < 0) { LM_ERR("cannot pop profile's has_value int\n"); return; } if (has_value) { if (!profile->has_value) { LM_WARN("The other end does not have a value for this profile:" "<%.*s> [node: %d]\n", profile->name.len, profile->name.s, packet->src_id); profile = NULL; } if (bin_pop_str(packet, &value)) { LM_ERR("cannot pop the value of the profile\n"); return; } } if (bin_pop_int(packet, &counter) < 0) { LM_ERR("cannot pop profile's counter\n"); return; } if (profile) { if (!profile->has_value) { lock_get(&profile->noval_repl_info->lock); destination = find_destination(profile->noval_repl_info, packet->src_id); if(destination == NULL){ lock_release(&profile->noval_repl_info->lock); return; } destination->counter = counter; destination->update = now; lock_release(&profile->noval_repl_info->lock); } else { /* XXX: hack to make sure we find the proper index */ i = core_hash(&value, NULL, profile->size); lock_set_get(profile->locks, i); /* if counter is 0 and we don't have it, don't try to create */ if (!counter) { dst = map_find(profile->entries[i], value); if (!dst) goto release; } else { dst = map_get(profile->entries[i], value); } if (!*dst) { rp = shm_malloc(sizeof(prof_value_info_t)); if (!rp) { LM_ERR("no more shm memory to allocate repl_prof_value\n"); goto release; } memset(rp, 0, sizeof(prof_value_info_t)); *dst = rp; } else { rp = (prof_value_info_t *) * dst; } if (!rp->noval) rp->noval = repl_prof_allocate(); if (rp->noval) { lock_release(&rp->noval->lock); destination = find_destination(rp->noval, packet->src_id); if (destination == NULL) { lock_release(&rp->noval->lock); lock_set_release(profile->locks, i); return; } destination->counter = counter; destination ->update = now; lock_release(&rp->noval->lock); } release: lock_set_release(profile->locks, i); } } } return; }
void rl_rcv_bin(int packet_type, struct receive_info *ri) { rl_algo_t algo; int limit; int counter; str name; int index; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; if (packet_type != RL_PIPE_COUNTER) return; /* match the server */ for (index = 0; index < rl_dests_nr; index++) { if (su_cmp(&ri->src_su, &rl_dests[index].to)) break; } if (index == rl_dests_nr) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } now = time(0); *rl_dests[index].last_msg = now; for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t) + rl_dests_nr * sizeof(rl_repl_counter_t)); (*pipe)->dsts = (rl_repl_counter_t *)((*pipe) + 1); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ (*pipe)->dsts[index].counter = counter; (*pipe)->dsts[index].update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
static void dlg_replicated_profiles(struct receive_info *ri) { int index; time_t now; str name; str value; char *ip; unsigned short port; unsigned int counter; struct dlg_profile_table *profile; int has_value; int i; void **dst; repl_prof_value_t *rp; /* optimize profile search */ struct dlg_profile_table *old_profile = NULL; str old_name; /* match the server */ for (index = 0; index < repl_prof_dests_nr; index++) { if (su_cmp(&ri->src_su, &repl_prof_dests[index].to)) break; } if (index == repl_prof_dests_nr) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } now = time(0); *repl_prof_dests[index].last_msg = now; for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ /* check if the same profile was sent */ if (!old_profile || old_name.len != name.len || memcmp(name.s, old_name.s, name.len) != 0) { old_profile = get_dlg_profile(&name); if (!old_profile) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("received unknown profile <%.*s> from %s:%hu\n", name.len, name.s, ip, port); } old_name = name; } profile = old_profile; if (bin_pop_int(&has_value) < 0) { LM_ERR("cannot pop profile's has_value int\n"); return; } if (has_value) { if (!profile->has_value) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("The other end does not have a value for this profile:" "<%.*s> [%s:%hu]\n", profile->name.len, profile->name.s, ip, port); profile = NULL; } if (bin_pop_str(&value)) { LM_ERR("cannot pop the value of the profile\n"); return; } } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop profile's counter\n"); return; } if (profile) { if (!profile->has_value) { lock_get(&profile->repl->lock); profile->repl->dsts[index].counter = counter; profile->repl->dsts[index].update = now; lock_release(&profile->repl->lock); } else { /* XXX: hack to make sure we find the proper index */ i = core_hash(&value, NULL, profile->size); lock_set_get(profile->locks, i); /* if counter is 0 and we don't have it, don't try to create */ if (!counter) { dst = map_find(profile->entries[i], value); if (!dst) goto release; } else { dst = map_get(profile->entries[i], value); } if (!*dst) { rp = shm_malloc(sizeof(repl_prof_value_t)); if (!rp) { LM_ERR("no more shm memory to allocate repl_prof_value\n"); goto release; } memset(rp, 0, sizeof(repl_prof_value_t)); *dst = rp; } else { rp = (repl_prof_value_t *)*dst; } if (!rp->noval) rp->noval = repl_prof_allocate(); if (rp->noval) { lock_release(&rp->noval->lock); rp->noval->dsts[index].counter = counter; rp->noval->dsts[index].update = now; lock_release(&rp->noval->lock); } release: lock_set_release(profile->locks, i); } } } return; }
void rl_rcv_bin(bin_packet_t *packet) { rl_algo_t algo; int limit; int counter; str name; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; if (packet->type != RL_PIPE_COUNTER) { LM_WARN("Invalid binary packet command: %d (from node: %d in cluster: %d)\n", packet->type, packet->src_id, rl_repl_cluster); return; } now = time(0); for (;;) { if (bin_pop_str(packet, &name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(packet, &algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(packet, &limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(packet, &counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, allocate it in case we need it later */ if (!(*pipe = rl_create_pipe(limit, algo))) goto release; LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); /* * XXX: do not output these warnings since they can be triggered * when a custom limit is used if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); */ } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, packet->src_id); if (!destination) goto release; destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
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; }
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; }
void rl_rcv_bin(int packet_type, struct receive_info *ri, int server_id) { rl_algo_t algo; int limit; int counter; str name; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; if (packet_type == SERVER_TEMP_DISABLED) { get_su_info(&ri->src_su.s, ip, port); LM_WARN("server: %s:%hu temporary disabled\n", ip, port); return; } if (packet_type == SERVER_TIMEOUT) { LM_WARN("server with clustererer id %d timeout\n", server_id); return; } if(get_bin_pkg_version() != BIN_VERSION){ LM_ERR("incompatible bin protocol version\n"); return; } if (packet_type != RL_PIPE_COUNTER) return; if (packet_type != RL_PIPE_COUNTER) return; now = time(0); for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t)); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, server_id); destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }
void rl_rcv_bin(int packet_type, struct receive_info *ri) { rl_algo_t algo; int limit; int counter; int rc; int server_id; str name; char *ip; unsigned short port; rl_pipe_t **pipe; unsigned int hash_idx; time_t now; rl_repl_counter_t *destination; LM_DBG("received a binary packet [%d]!\n", packet_type); if (packet_type != RL_PIPE_COUNTER) return; rc = bin_pop_int(&server_id); if (rc < 0) return; if (!clusterer_api.check(accept_repl_pipes, &ri->src_su, server_id, ri->proto)){ get_su_info(&ri->src_su.s, ip, port); LM_WARN("received bin packet from unknown source: %s:%hu\n", ip, port); return; } now = time(0); for (;;) { if (bin_pop_str(&name) == 1) break; /* pop'ed all pipes */ if (bin_pop_int(&algo) < 0) { LM_ERR("cannot pop pipe's algorithm\n"); return; } if (bin_pop_int(&limit) < 0) { LM_ERR("cannot pop pipe's limit\n"); return; } if (bin_pop_int(&counter) < 0) { LM_ERR("cannot pop pipe's counter\n"); return; } hash_idx = RL_GET_INDEX(name); RL_GET_LOCK(hash_idx); /* try to get the value */ pipe = RL_GET_PIPE(hash_idx, name); if (!pipe) { LM_ERR("cannot get the index\n"); goto release; } if (!*pipe) { /* if the pipe does not exist, alocate it in case we need it later */ *pipe = shm_malloc(sizeof(rl_pipe_t)); if (!*pipe) { LM_ERR("no more shm memory\n"); goto release; } memset(*pipe, 0, sizeof(rl_pipe_t)); LM_DBG("Pipe %.*s doesn't exist, but was created %p\n", name.len, name.s, *pipe); (*pipe)->algo = algo; (*pipe)->limit = limit; } else { LM_DBG("Pipe %.*s found: %p - last used %lu\n", name.len, name.s, *pipe, (*pipe)->last_used); if ((*pipe)->algo != algo) LM_WARN("algorithm %d different from the initial one %d for " "pipe %.*s", algo, (*pipe)->algo, name.len, name.s); if ((*pipe)->limit != limit) LM_WARN("limit %d different from the initial one %d for " "pipe %.*s", limit, (*pipe)->limit, name.len, name.s); } /* set the last used time */ (*pipe)->last_used = time(0); /* set the destination's counter */ destination = find_destination(*pipe, server_id); destination->counter = counter; destination->update = now; RL_RELEASE_LOCK(hash_idx); } return; release: RL_RELEASE_LOCK(hash_idx); }