Exemplo n.º 1
0
static int receive_urecord_delete(bin_packet_t *packet)
{
	str d, aor;
	udomain_t *domain;

	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 out_err;
	}

	lock_udomain(domain, &aor);

	if (delete_urecord(domain, &aor, NULL, 1) != 0) {
		unlock_udomain(domain, &aor);
		goto out_err;
	}

	unlock_udomain(domain, &aor);

	return 0;

out_err:
	LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Exemplo n.º 2
0
/**
 * Note: prevents the creation of any duplicate AoR
 */
static int receive_urecord_insert(bin_packet_t *packet)
{
	str d, aor;
	urecord_t *r;
	udomain_t *domain;

	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 out_err;
	}

	lock_udomain(domain, &aor);

	if (get_urecord(domain, &aor, &r) == 0)
		goto out;

	if (insert_urecord(domain, &aor, &r, 1) != 0) {
		unlock_udomain(domain, &aor);
		goto out_err;
	}

out:
	unlock_udomain(domain, &aor);

	return 0;

out_err:
	LM_ERR("failed to replicate event locally. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Exemplo n.º 3
0
/**
 * replicates the remote deletion of a dialog locally
 * by reading the relevant information using the Binary Packet Interface
 */
int dlg_replicated_delete(void)
{
	str call_id, from_tag, to_tag;
	unsigned int dir, dst_leg;
	struct dlg_cell *dlg;
	int old_state, new_state, unref, ret;

	bin_pop_str(&call_id);
	bin_pop_str(&from_tag);
	bin_pop_str(&to_tag);

	LM_DBG("Deleting dialog with callid: %.*s\n", call_id.len, call_id.s);

	dlg = get_dlg(&call_id, &from_tag, &to_tag, &dir, &dst_leg);
	if (!dlg) {
	        LM_ERR("dialog not found (callid: |%.*s| ftag: |%.*s|\n",
	                call_id.len, call_id.s, from_tag.len, from_tag.s);
	        return -1;
	}

	destroy_linkers(dlg->profile_links);
	dlg->profile_links = NULL;

	next_state_dlg(dlg, DLG_EVENT_REQBYE, &old_state, &new_state, &unref);

	if (old_state == new_state) {
		LM_ERR("duplicate dialog delete request (callid: |%.*s|"
		       "ftag: |%.*s|\n", call_id.len, call_id.s, from_tag.len, from_tag.s);
		return -1;
	}

	ret = remove_dlg_timer(&dlg->tl);
	if (ret < 0) {
		LM_CRIT("unable to unlink the timer on 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));
	} else if (ret > 0) {
		LM_DBG("dlg expired (not in timer list) on 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));
	} else {
		/* dialog sucessfully removed from timer -> unref */
		unref++;
	}

	unref_dlg(dlg, 1 + unref);
	if_update_stat(dlg_enable_stats, active_dlgs, -1);

	return 0;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
static int receive_shtag_active_msg(bin_packet_t *packet)
{
	str tag_name;
	struct dlg_sharing_tag *tag;

	bin_pop_str(packet, &tag_name);

	lock_start_write(shtags_lock);

	if ((tag = get_shtag_unsafe(&tag_name)) == NULL) {
		LM_ERR("Unable to fetch sharing tag\n");
		lock_stop_write(shtags_lock);
		return -1;
	}

	/* directly go to backup state when another
	 * node in the cluster is to active */
	tag->state = SHTAG_STATE_BACKUP;

	tag->send_active_msg = 0;
	free_active_msgs_info(tag);

	lock_stop_write(shtags_lock);

	return 0;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
/**
 * 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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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);
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
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);
}
Exemplo n.º 13
0
static int receive_ucontact_update(bin_packet_t *packet)
{
	static ucontact_info_t ci;
	static str d, aor, host, contact_str, callid,
		user_agent, path, attr, st, sock;
	udomain_t *domain;
	urecord_t *record;
	ucontact_t *contact;
	int port, proto;
	int rc;

	memset(&ci, 0, sizeof ci);

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

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

	bin_pop_str(packet, &contact_str);

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

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

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

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

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

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

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

	bin_pop_str(packet, &sock);

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

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

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

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

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

	if (skip_replicated_db_ops)
		ci.flags |= FL_MEM;

	lock_udomain(domain, &aor);

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

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

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

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

	unlock_udomain(domain, &aor);

	return 0;

error:
	LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Exemplo n.º 14
0
static int receive_ucontact_insert(bin_packet_t *packet)
{
	static ucontact_info_t ci;
	static str d, aor, host, contact_str, callid,
		user_agent, path, attr, st, sock;
	udomain_t *domain;
	urecord_t *record;
	ucontact_t *contact;
	int rc, port, proto;

	memset(&ci, 0, sizeof ci);

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

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

	bin_pop_str(packet, &contact_str);

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

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

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

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

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

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

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

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

	bin_pop_str(packet, &sock);

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

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

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

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

	if (skip_replicated_db_ops)
		ci.flags |= FL_MEM;

	lock_udomain(domain, &aor);

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

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

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

	unlock_udomain(domain, &aor);
	return 0;

error:
	LM_ERR("failed to process replication event. dom: '%.*s', aor: '%.*s'\n",
		d.len, d.s, aor.len, aor.s);
	return -1;
}
Exemplo n.º 15
0
/**
 * 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;
}
Exemplo n.º 16
0
/**
 * 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;
}
Exemplo n.º 17
0
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);
}