예제 #1
0
파일: sca.c 프로젝트: 4N7HR4X/kamailio
static int sca_bind_srdb1( sca_mod *scam, db_func_t *db_api )
{
    db1_con_t	*db_con = NULL;
    int		rc = -1;

    if ( db_bind_mod( scam->cfg->db_url, db_api ) != 0 ) {
	LM_ERR( "Failed to initialize required DB API - %.*s\n", STR_FMT( scam->cfg->db_url));
	goto done;
    }
    scam->db_api = db_api;

    if ( !DB_CAPABILITY( (*db_api), DB_CAP_ALL )) {
	LM_ERR( "Selected database %.*s lacks required capabilities\n",
		STR_FMT( scam->cfg->db_url ));
	goto done;
    }

    /* ensure database exists and table schemas are correct */
    db_con = db_api->init( scam->cfg->db_url );
    if ( db_con == NULL ) {
	LM_ERR( "sca_bind_srdb1: failed to connect to DB %.*s\n",
		STR_FMT( scam->cfg->db_url ));
	goto done;
    }

    if ( db_check_table_version( db_api, db_con,
	    scam->cfg->subs_table, SCA_DB_SUBSCRIPTIONS_TABLE_VERSION ) < 0 ) {
	LM_ERR( "Version check of %.*s table in DB %.*s failed\n",
		STR_FMT( scam->cfg->subs_table ), STR_FMT( scam->cfg->db_url ));
	LM_ERR( "%.*s table version %d required\n",
		STR_FMT( scam->cfg->subs_table ),
		SCA_DB_SUBSCRIPTIONS_TABLE_VERSION );
	goto done;
    }

    /* DB and tables are OK, close DB handle. reopen in each child. */
    rc = 0;

done:
    if ( db_con != NULL ) {
	db_api->close( db_con );
	db_con = NULL;
    }

    return( rc );
}
예제 #2
0
str *call_query_udp(char **out, struct callmaster *m) {
	struct call *c;
	str *ret, callid, fromtag, totag;
	struct call_stats stats;

	__C_DBG("got query for callid '%s'", out[RE_UDP_DQ_CALLID]);

	str_init(&callid, out[RE_UDP_DQ_CALLID]);
	str_init(&fromtag, out[RE_UDP_DQ_FROMTAG]);
	str_init(&totag, out[RE_UDP_DQ_TOTAG]);

	c = call_get_opmode(&callid, m, OP_OTHER);
	if (!c) {
		ilog(LOG_INFO, "["STR_FORMAT"] Call-ID to query not found", STR_FMT(&callid));
		goto err;
	}

	ng_call_stats(c, &fromtag, &totag, NULL, &stats);

	rwlock_unlock_w(&c->master_lock);

	ret = str_sprintf("%s %lld "UINT64F" "UINT64F" "UINT64F" "UINT64F"\n", out[RE_UDP_COOKIE],
		(long long int) m->conf.silent_timeout - (poller_now - stats.last_packet),
		stats.totals[0].packets, stats.totals[1].packets,
		stats.totals[2].packets, stats.totals[3].packets);
	goto out;

err:
	if (c)
		rwlock_unlock_w(&c->master_lock);
	ret = str_sprintf("%s E8\n", out[RE_UDP_COOKIE]);
	goto out;

out:
	if (c)
		obj_put(c);
	return ret;
}
예제 #3
0
/**
 * @brief pings the servers in the nodelist
 *
 * if the server does not reply to the ping, it is removed from the list
 * the ping messages are actualy notification requests
 * this way the ping will have two uses:
 *   - checks if the servers in the list are up and running
 *   - updates the list of servers from the other nodes
 */
void ping_servers(unsigned int ticks, void *param)
{
	str *body;
	int ret;
	LM_DBG("ping_servers\n");

	if(!node_list->nodes
			|| (node_list->nodes->local && !node_list->nodes->next)) {
		LM_DBG("node list is empty - attempt to rebuild from notification "
			   "address\n");
		*dmq_init_callback_done = 0;
		if(dmq_notification_address.s) {
			notification_node =
					add_server_and_notify(&dmq_notification_address);
			if(!notification_node) {
				LM_ERR("cannot retrieve initial nodelist from %.*s\n",
						STR_FMT(&dmq_notification_address));
			}
		} else {
			LM_ERR("no notification address");
		}
		return;
	}

	body = build_notification_body();
	if(!body) {
		LM_ERR("could not build notification body\n");
		return;
	}
	ret = bcast_dmq_message1(dmq_notification_peer, body, NULL,
			&notification_callback, 1, &notification_content_type, 1);
	pkg_free(body->s);
	pkg_free(body);
	if(ret < 0) {
		LM_ERR("error broadcasting message\n");
	}
}
예제 #4
0
/**
 * @brief set the parameters for the node
 */
int set_dmq_node_params(dmq_node_t* node, param_t* params)
{
	str* status;
	if(!params) {
		LM_DBG("no parameters given\n");
		return 0;
	}
	status = get_param_value(params, &dmq_node_status_str);
	if(status) {
		if(STR_EQ(*status, dmq_node_active_str)) {
			node->status = DMQ_NODE_ACTIVE;
		} else if(STR_EQ(*status, dmq_node_timeout_str)) {
			node->status = DMQ_NODE_TIMEOUT;
		} else if(STR_EQ(*status, dmq_node_disabled_str)) {
			node->status = DMQ_NODE_DISABLED;
		} else {
			LM_ERR("invalid status parameter: %.*s\n", STR_FMT(status));
			goto error;
		}
	}
	return 0;
error:
	return -1;
}
예제 #5
0
파일: sca_notify.c 프로젝트: caruizdiaz/sca
    static dlg_t *
sca_notify_dlg_for_subscription( sca_subscription *sub )
{
    dlg_t		*dlg;

    dlg = (dlg_t *)pkg_malloc( sizeof( dlg_t ));
    if ( dlg == NULL ) {
	LM_ERR( "pkg_malloc dlg_t for %.*s failed: out of memory",
		STR_FMT( &sub->subscriber ));
	return( NULL );
    }
    memset( dlg, 0, sizeof( dlg_t ));

    dlg->loc_seq.value = sub->dialog.notify_cseq;
    dlg->loc_seq.is_set = 1;

    dlg->id.call_id = sub->dialog.call_id;
    dlg->id.rem_tag = sub->dialog.from_tag;
    dlg->id.loc_tag = sub->dialog.to_tag;

    /* RURI */
    dlg->rem_target = sub->subscriber;

    /* To and From URIs are both the SCA AoR in an SCA NOTIFY */
    dlg->loc_uri = sub->target_aor;
    dlg->rem_uri = sub->target_aor;

    /*
     * the dialog state in an SCA NOTIFY should always be confirmed,
     * since we generated the dialog to-tag in our response to the
     * subscriber's SUBSCRIBE request.
     */
    dlg->state = DLG_CONFIRMED;

    return( dlg );
}
예제 #6
0
int worker_reg_send_impl(ei_cnode *ec, int s,int wpid)
{
	str server = STR_NULL;
	ei_x_buff emsg;
	struct msghdr msgh;
	struct iovec cnt[6];
	int rc;

	memset((void*)&emsg,0,sizeof(emsg));

	memset((void*)&msgh,0,sizeof(msgh));

	/* server name length */
	cnt[0].iov_base = &server.len;
	cnt[0].iov_len  = sizeof(int);

	/* Erlang args size */
	cnt[1].iov_base = &emsg.buffsz;
	cnt[1].iov_len  = sizeof(int);

	/* get data size */
	msgh.msg_iov    = cnt;
	msgh.msg_iovlen = 2;

	while ((rc = recvmsg(s, &msgh, MSG_PEEK)) == -1 && errno == EAGAIN)
		;

	if (rc == -1){
		LM_ERR("recvmsg failed (socket=%d): %s\n",s,strerror(errno));
		return -1;
	}

	/* allocate space */
	server.s = (char*)pkg_malloc(server.len+1);
	if (!server.s) {
		LM_ERR("not enough memory\n");
		goto err;
	}

	emsg.buff = (char*)malloc(emsg.buffsz);
	if (!emsg.buff) {
		LM_ERR("malloc: not enough memory\n");
		goto err;
	}

	/* buffers */
	cnt[2].iov_base = server.s;
	cnt[2].iov_len  = server.len;

	cnt[3].iov_base = emsg.buff;
	cnt[3].iov_len  = emsg.buffsz;

	/* get whole data */
	msgh.msg_iovlen = 4;
	while ((rc = recvmsg(s, &msgh, MSG_WAITALL)) == -1 && errno == EAGAIN)
		;

	if (rc == -1){
		LM_ERR("recvmsg failed (socket=%d): %s\n",s,strerror(errno));
		goto err;
	}

	/* fix str */
	server.s[server.len] = 0;

	if(!enode) {
		LM_NOTICE("there is no connected Erlang node\n");
		goto err;
	}

	LM_DBG(">> {%.*s,'%s'} ! emsg\n",STR_FMT(&server),enode->conn.nodename);

	EI_X_BUFF_PRINT(&emsg);

	/* do ERL_REG_SEND */
	if ((rc = ei_reg_send(ec,enode->sockfd,server.s,emsg.buff,emsg.buffsz)) == ERL_ERROR)
	{
		if (erl_errno)
		{
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>: %s\n",enode->conn.nodename,enode->sockfd,strerror(erl_errno));
		}
		else if (errno)
		{
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>: %s\n",enode->conn.nodename,enode->sockfd,strerror(errno));
		}
		else
		{
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>, Unknown error.\n",ec->thisalivename,enode->sockfd);
		}
	}

	pkg_free(server.s);
	free(emsg.buff);

	return 0;

err:
	pkg_free(server.s);
	free(emsg.buff);

	return -1;
}
예제 #7
0
/**
 * @brief build a dmq node
 */
dmq_node_t *build_dmq_node(str *uri, int shm)
{
	dmq_node_t *ret = NULL;
	param_hooks_t hooks;
	param_t *params;

	/* For DNS-Lookups */
	static char hn[256];
	struct hostent *he;

	LM_DBG("build_dmq_node %.*s with %s memory\n", STR_FMT(uri),
			shm ? "shm" : "private");

	if(shm) {
		ret = shm_malloc(sizeof(dmq_node_t));
		if(ret == NULL) {
			LM_ERR("no more shm\n");
			goto error;
		}
		memset(ret, 0, sizeof(dmq_node_t));
		if(shm_str_dup(&ret->orig_uri, uri) < 0) {
			goto error;
		}
	} else {
		ret = pkg_malloc(sizeof(dmq_node_t));
		if(ret == NULL) {
			LM_ERR("no more pkg\n");
			goto error;
		}
		memset(ret, 0, sizeof(dmq_node_t));
		if(pkg_str_dup(&ret->orig_uri, uri) < 0) {
			goto error;
		}
	}
	set_default_dmq_node_params(ret);
	if(parse_uri(ret->orig_uri.s, ret->orig_uri.len, &ret->uri) < 0
			|| ret->uri.host.len > 254) {
		LM_ERR("error parsing uri\n");
		goto error;
	}
	/* if any parameters found, parse them */
	if(parse_params(&ret->uri.params, CLASS_ANY, &hooks, &params) < 0) {
		LM_ERR("error parsing params\n");
		goto error;
	}
	/* if any params found */
	if(params) {
		if(set_dmq_node_params(ret, params) < 0) {
			free_params(params);
			LM_ERR("error setting parameters\n");
			goto error;
		}
		free_params(params);
	} else {
		LM_DBG("no dmqnode params found\n");
	}
	/* resolve hostname */
	strncpy(hn, ret->uri.host.s, ret->uri.host.len);
	hn[ret->uri.host.len] = '\0';
	he = resolvehost(hn);
	if(he == 0) {
		LM_ERR("could not resolve %.*s\n", ret->uri.host.len, ret->uri.host.s);
		goto error;
	}
	hostent2ip_addr(&ret->ip_address, he, 0);

	return ret;

error:
	if(ret != NULL) {
		destroy_dmq_node(ret, shm);
	}
	return NULL;
}
예제 #8
0
static void control_udp_incoming(struct obj *obj, str *buf, const endpoint_t *sin, char *addr,
		struct udp_listener *ul) {
	struct control_udp *u = (void *) obj;
	int ret;
	int ovec[100];
	char **out;
	struct iovec iov[10];
	unsigned int iovlen;
	str cookie, *reply;

	ret = pcre_exec(u->parse_re, u->parse_ree, buf->s, buf->len, 0, 0, ovec, G_N_ELEMENTS(ovec));
	if (ret <= 0) {
		ret = pcre_exec(u->fallback_re, NULL, buf->s, buf->len, 0, 0, ovec, G_N_ELEMENTS(ovec));
		if (ret <= 0) {
			ilog(LOG_WARNING, "Unable to parse command line from udp:%s: %.*s", addr, STR_FMT(buf));
			return;
		}

		ilog(LOG_WARNING, "Failed to properly parse UDP command line '%.*s' from %s, using fallback RE", STR_FMT(buf), addr);

		pcre_get_substring_list(buf->s, ovec, ret, (const char ***) &out);

		iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
		iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
		if (out[RE_UDP_UL_CMD] && (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U' || chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L')) {
			iov[1].iov_base = (void *) out[4];
			iov[1].iov_len = strlen(out[4]);
			iov[2].iov_base = (void *) out[3];
			iov[2].iov_len = strlen(out[3]);
			iov[3].iov_base = "\n";
			iov[3].iov_len = 1;
			iovlen = 4;
		}
		else {
			iov[1].iov_base = " E8\n";
			iov[1].iov_len = 4;
			iovlen = 2;
		}

		socket_sendiov(&ul->sock, iov, iovlen, sin);

		pcre_free(out);

		return;
	}

	ilog(LOG_INFO, "Got valid command from udp:%s: %.*s", addr, STR_FMT(buf));

	pcre_get_substring_list(buf->s, ovec, ret, (const char ***) &out);

	str_init(&cookie, (void *) out[RE_UDP_COOKIE]);
	reply = cookie_cache_lookup(&u->cookie_cache, &cookie);
	if (reply) {
		ilog(LOG_INFO, "Detected command from udp:%s as a duplicate", addr);
		socket_sendto(&ul->sock, reply->s, reply->len, sin);
		free(reply);
		goto out;
	}

	if (out[RE_UDP_UL_CALLID])
		log_info_c_string(out[RE_UDP_UL_CALLID]);
	else if (out[RE_UDP_DQ_CALLID])
		log_info_c_string(out[RE_UDP_DQ_CALLID]);

	if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'U')
		reply = call_update_udp(out, u->callmaster, addr, sin);
	else if (chrtoupper(out[RE_UDP_UL_CMD][0]) == 'L')
		reply = call_lookup_udp(out, u->callmaster);
	else if (chrtoupper(out[RE_UDP_DQ_CMD][0]) == 'D')
		reply = call_delete_udp(out, u->callmaster);
	else if (chrtoupper(out[RE_UDP_DQ_CMD][0]) == 'Q')
		reply = call_query_udp(out, u->callmaster);
	else if (chrtoupper(out[RE_UDP_V_CMD][0]) == 'V') {
		iovlen = 2;

		iov[0].iov_base = (void *) out[RE_UDP_COOKIE];
		iov[0].iov_len = strlen(out[RE_UDP_COOKIE]);
		iov[1].iov_base = " ";
		iov[1].iov_len = 1;

		if (chrtoupper(out[RE_UDP_V_FLAGS][0]) == 'F') {
			ret = 0;
			if (!strcmp(out[RE_UDP_V_PARMS], "20040107"))
				ret = 1;
			else if (!strcmp(out[RE_UDP_V_PARMS], "20050322"))
				ret = 1;
			else if (!strcmp(out[RE_UDP_V_PARMS], "20060704"))
				ret = 1;
			iov[2].iov_base = ret ? "1\n" : "0\n";
			iov[2].iov_len = 2;
			iovlen++;
		}
		else {
			iov[2].iov_base = "20040107\n";
			iov[2].iov_len = 9;
			iovlen++;
		}
		socket_sendiov(&ul->sock, iov, iovlen, sin);
	}

	if (reply) {
		socket_sendto(&ul->sock, reply->s, reply->len, sin);
		cookie_cache_insert(&u->cookie_cache, &cookie, reply);
		free(reply);
	}
	else
		cookie_cache_remove(&u->cookie_cache, &cookie);

out:
	pcre_free(out);
	log_info_clear();
}
예제 #9
0
/* 
 * Loads contacts in destination set into contacts_avp in reverse
 * priority order and associated each contact with Q_FLAG telling if
 * contact is the last one in its priority class.  Finally, removes
 * all branches from destination set.
 */
int t_load_contacts(struct sip_msg* msg, char* key, char* value)
{
    str uri, tmp, dst_uri, path, branch_info, *ruri;
    qvalue_t first_q, q;
    struct contact *contacts, *next, *prev, *curr;
    int_str val;
    int first_idx, idx;
    struct socket_info* sock;
    unsigned int flags;

    /* Check if contacts_avp has been defined */
    if (contacts_avp.n == 0) {
		LM_ERR("feature has been disabled - "
		       "to enable define contacts_avp module parameter");
		return -1;
    }

    /* Check if anything needs to be done */
    if (nr_branches == 0) {
		LM_DBG("t_load_contacts(): nothing to do - no branches!\n");
		return 1;
    }

    ruri = (str *)0;

    /* Take first q from Request-URI */
    ruri = GET_RURI(msg);
    if (!ruri) {
	LM_ERR("no Request-URI found\n");
	return -1;
    }
    first_q = get_ruri_q();
    first_idx = 0;

    /* Check if all q values are equal */
    for(idx = first_idx; (tmp.s = get_branch(idx, &tmp.len, &q, 0, 0, 0, 0))
			!= 0; idx++) {
		if (q != first_q) {
			goto rest;
		}
    }

    LM_DBG("t_load_contacts(): nothing to do - all contacts have same q!\n");
    return 1;

rest:

    /* Allocate memory for first contact */
    contacts = (struct contact *)pkg_malloc(sizeof(struct contact));
    if (!contacts) {
		LM_ERR("no memory for contact info\n");
		return -1;
    }

    /* Insert Request-URI branch to first contact */
    contacts->uri.s = ruri->s;
    contacts->uri.len = ruri->len;
    contacts->dst_uri = msg->dst_uri;
    contacts->sock = msg->force_send_socket;
    getbflagsval(0, &contacts->flags);
    contacts->path = msg->path_vec;
    contacts->q = first_q;
    contacts->next = (struct contact *)0;

    /* Insert (remaining) branches to contact list in increasing q order */

    for(idx = first_idx;
		(uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock))
			!= 0;
		idx++ ) {
		next = (struct contact *)pkg_malloc(sizeof(struct contact));
		if (!next) {
			LM_ERR("no memory for contact info\n");
			free_contact_list(contacts);
			return -1;
		}
		next->uri = uri;
		next->q = q;
		next->dst_uri = dst_uri;
		next->path = path;
		next->flags = flags;
		next->sock = sock;
		next->next = (struct contact *)0;
		prev = (struct contact *)0;
		curr = contacts;
		while (curr && (curr->q < q)) {
			prev = curr;
			curr = curr->next;
		}
		if (!curr) {
			next->next = (struct contact *)0;
			prev->next = next;
		} else {
			next->next = curr;
			if (prev) {
				prev->next = next;
			} else {
				contacts = next;
			}
		}    
    }

    /* Assign values for q_flags */
    curr = contacts;
    curr->q_flag = 0;
    while (curr->next) {
		if (curr->q < curr->next->q) {
			curr->next->q_flag = Q_FLAG;
		} else {
			curr->next->q_flag = 0;
		}
		curr = curr->next;
    }

    /* Add contacts to contacts_avp */
    curr = contacts;
    while (curr) {
		if (encode_branch_info(&branch_info, curr) == 0) {
			LM_ERR("encoding of branch info failed\n");
			free_contact_list(contacts);
			if (branch_info.s) pkg_free(branch_info.s);
			return -1;
		}
		val.s = branch_info;
		add_avp(contacts_avp_type|AVP_VAL_STR|(curr->q_flag),
				contacts_avp, val);
		pkg_free(branch_info.s);
		LM_DBG("loaded contact <%.*s> with q_flag <%d>\n",
		       STR_FMT(&val.s), curr->q_flag);
		curr = curr->next;
    }

    /* Clear all branches */
    clear_branches();

    /* Free contact list */
    free_contact_list(contacts);

    return 1;
}
예제 #10
0
static int get_str(str *str_ptr, erl_rpc_ctx_t *ctx, int reads, int autoconvert)
{
	int type, size;
	char *p;
	double d;
	long n;

	if (ei_get_type(ctx->request->buff,&ctx->request_index,&type,&size))
	{
		erl_rpc_fault(ctx,400,"Can't determine data type of parameter #%d",reads);
		return -1;
	}

	switch(type)
	{
	case ERL_FLOAT_EXT:

		if (autoconvert == 0)
		{
			erl_rpc_fault(ctx,400,"Bad type of parameter #%d",reads);
			return -1;
		}

		if (ei_decode_double(ctx->request->buff,&ctx->request_index,&d))
		{
			erl_rpc_fault(ctx,400, "Bad value of parameter #%d.",reads);
			return -1;
		}

		p=(char*)pkg_malloc(MAX_DIGITS);

		if (!p)
		{
			erl_rpc_fault(ctx,500, "Internal Server Error (No memory left)");
			LM_ERR("Not enough memory\n");
			return -1;
		}

		if (add_to_recycle_bin(JUNK_PKGCHAR, p, ctx))
		{
			pkg_free(p);
			return -1;
		}

		str_ptr->len=snprintf(p, MAX_DIGITS, "%f", d);
		str_ptr->s = p;

		break;

	case ERL_STRING_EXT:
	case ERL_LIST_EXT:
	case ERL_BINARY_EXT:

		/* allocate buffer */
		p = (char*)pkg_malloc(size+1);

		if (!p)
		{
			erl_rpc_fault(ctx,500, "Internal Server Error (No memory left)");
			LM_ERR("Not enough memory\n");
			return -1;
		}

		if (add_to_recycle_bin(JUNK_PKGCHAR, p, ctx))
		{
			pkg_free(p);
			return -1;
		}

		if(ei_decode_strorbin(ctx->request->buff,&ctx->request_index,size+1,p))
		{
			erl_rpc_fault(ctx,400, "Can't read parameter #%d",reads);
			return -1;
		}

		str_ptr->s=p;
		str_ptr->len=size;

		break;

	case ERL_SMALL_INTEGER_EXT:
	case ERL_INTEGER_EXT:

		if (autoconvert == 0)
		{
			erl_rpc_fault(ctx,400,"Bad type of parameter #%d",reads);
			return -1;
		}

		if (ei_decode_long(ctx->request->buff,&ctx->request_index,&n))
		{
			erl_rpc_fault(ctx,400, "Bad value of parameter #%d.",reads);
			return -1;
		}

		p=(char*)pkg_malloc(MAX_DIGITS);

		if (!p)
		{
			erl_rpc_fault(ctx,500, "Internal Server Error (No memory left)");
			LM_ERR("Not enough memory\n");
			return -1;
		}

		if (add_to_recycle_bin(JUNK_PKGCHAR, p, ctx))
		{
			pkg_free(p);
			return -1;
		}

		str_ptr->len=snprintf(p, MAX_DIGITS, "%ld", n);
		str_ptr->s = p;

		break;
	default:
		erl_rpc_fault(ctx,400,"Can't convert to string parameter #%d.",reads);
		return -1;
	}

	LM_ERR("parameter #%d:<%.*s>\n",reads,STR_FMT(str_ptr));

	return 0;
}
예제 #11
0
파일: ice.c 프로젝트: Zodiac-Evil/rtpengine
/* called with the call lock held in W, hence agent doesn't need to be locked */
void ice_update(struct ice_agent *ag, struct stream_params *sp) {
	GList *l, *k;
	struct ice_candidate *cand, *dup;
	struct call_media *media;
	struct call *call;
	int recalc = 0;
	unsigned int comps;
	struct packet_stream *components[MAX_COMPONENTS], *ps;
	GQueue *candidates;

	if (!ag)
		return;

	atomic64_set(&ag->last_activity, poller_now);
	media = ag->media;
	call = media->call;

	__role_change(ag, MEDIA_ISSET(media, ICE_CONTROLLING));

	if (sp) {
		/* check for ICE restarts */
		if (ag->ufrag[0].s && sp->ice_ufrag.s && str_cmp_str(&ag->ufrag[0], &sp->ice_ufrag))
			__ice_restart(ag);
		else if (ag->pwd[0].s && sp->ice_pwd.s && str_cmp_str(&ag->pwd[0], &sp->ice_pwd))
			__ice_restart(ag);
		else if (ag->local_interface != media->interface)
			__ice_restart(ag);

		/* update remote info */
		if (sp->ice_ufrag.s)
			call_str_cpy(call, &ag->ufrag[0], &sp->ice_ufrag);
		if (sp->ice_pwd.s)
			call_str_cpy(call, &ag->pwd[0], &sp->ice_pwd);

		candidates = &sp->ice_candidates;
	}
	else /* this is a dummy update in case rtcp-mux has changed */
		candidates = &ag->remote_candidates;

	/* get our component streams */
	ZERO(components);
	comps = 0;
	for (l = media->streams.head; l; l = l->next)
		components[comps++] = l->data;
	if (comps == 2 && MEDIA_ISSET(media, RTCP_MUX))
		components[1] = NULL;

	comps = 0;
	for (l = candidates->head; l; l = l->next) {
		if (ag->remote_candidates.length >= MAX_ICE_CANDIDATES) {
			ilog(LOG_WARNING, "Maxmimum number of ICE candidates exceeded");
			break;
		}

		cand = l->data;

		/* skip invalid */
		if (!cand->component_id || cand->component_id > G_N_ELEMENTS(components))
			continue;
		ps = components[cand->component_id - 1];

		if (ps) /* only count active components */
			comps = MAX(comps, cand->component_id);

		dup = g_hash_table_lookup(ag->candidate_hash, cand);
		if (!sp && dup) /* this isn't a real update, so only check pairings */
			goto pair;

		/* check for duplicates */
		if (dup) {
			/* if this is peer reflexive, we've learned it through STUN.
			 * otherwise it's simply one we've seen before. */
			if (dup->type == ICT_PRFLX) {
				ilog(LOG_DEBUG, "Replacing previously learned prflx ICE candidate with "
						STR_FORMAT":%lu", STR_FMT(&cand->foundation),
						cand->component_id);
			}
			else {
				/* if the new one has higher priority then the old one, then we
				 * update it, otherwise we just drop it */
				if (cand->priority <= dup->priority) {
					ilog(LOG_DEBUG, "Dropping new ICE candidate "STR_FORMAT" in favour of "
							STR_FORMAT":%lu",
							STR_FMT(&cand->foundation),
							STR_FMT(&dup->foundation), cand->component_id);
					continue;
				}

				ilog(LOG_DEBUG, "Replacing known ICE candidate "STR_FORMAT" with higher "
						"priority "
						STR_FORMAT":%lu",
						STR_FMT(&dup->foundation),
						STR_FMT(&cand->foundation), cand->component_id);
			}

			/* priority and foundation may change */
			g_hash_table_remove(ag->foundation_hash, dup);
			recalc += __copy_cand(call, dup, cand);
		}
		else {
			ilog(LOG_DEBUG, "Learning new ICE candidate "STR_FORMAT":%lu",
					STR_FMT(&cand->foundation), cand->component_id);
			dup = g_slice_alloc(sizeof(*dup));
			__copy_cand(call, dup, cand);
			g_hash_table_insert(ag->candidate_hash, dup, dup);
			g_queue_push_tail(&ag->remote_candidates, dup);
		}

		g_hash_table_insert(ag->foundation_hash, dup, dup);

pair:
		if (!ps)
			continue;
		for (k = ag->local_interface->list.head; k; k = k->next) {
			/* skip duplicates here also */
			if (__pair_lookup(ag, dup, k->data))
				continue;
			__pair_candidate(k->data, ag, dup, ps);
		}
	}

	if (comps)
		ag->active_components = comps;
	if (!ag->active_components) {
		/* determine components for tricke-ice case */
		comps = 2;
		if (!components[1])
			comps = 1;
		ag->active_components = comps;
	}

	/* if we're here, we can start our ICE checks */
	if (recalc)
		__recalc_pair_prios(ag);
	else
		__all_pairs_list(ag);

	if (comps)
		__do_ice_checks(ag);
	else
		__agent_shutdown(ag);
}
예제 #12
0
/* Encode branch info from str */
static inline int decode_branch_info(char *info, str *uri, str *dst, str *path,
									 struct socket_info **sock,
									 unsigned int *flags)
{
    str s, host;
    int port, proto;
    char *pos, *at, *tmp;

	if (info == NULL) {
		ERR("decode_branch_info: Invalid input string.\n");
		return 0;
	}
	
	/* Reset or return arguments to sane defaults */
	uri->s = 0; uri->len = 0;
	dst->s = 0; dst->len = 0;
	path->s = 0; path->len = 0;
	*sock = NULL;
	*flags = 0;
	
	/* Make sure that we have at least a non-empty URI string, it is fine if
	 * everything else is missing, but we need at least the URI. */
	uri->s = info; 
	if ((pos = strchr(info, '\n')) == NULL) { 
		uri->len = strlen(info); 
			/* We don't even have the URI string, this is bad, report an
			 * error. */
		if (uri->len == 0) goto uri_missing;
		return 1;
    }
	uri->len = pos - info;
	if (uri->len == 0) goto uri_missing;

	/* If we get here we have at least the branch URI, now try to parse as
	 * much as you can. All output variable have been initialized above, so it
	 * is OK if any of the fields are missing from now on. */
    dst->s = at = pos + 1;
    if ((pos = strchr(at, '\n')) == NULL) {
		dst->len = strlen(dst->s);
		return 1;
    }
	dst->len = pos - at;

    path->s = at = pos + 1;
    if ((pos = strchr(at, '\n')) == NULL) {
		path->len = strlen(path->s);
		return 1;
    }
    path->len = pos - at;

    s.s = at = pos + 1;
    if ((pos = strchr(at, '\n')) == NULL) {
		/* No LF found, that means we take the string till the final zero
		 * termination character and pass it directly to parse_phostport
		 * without making a zero-terminated copy. */
		tmp = s.s;
		s.len = strlen(s.s);
	} else {
		/* Our string is terminated by LF, so we need to make a
		 * zero-terminated copy of the string before we pass it to
		 * parse_phostport. */
		s.len = pos - at;
		if ((tmp = as_asciiz(&s)) == NULL) {
			ERR("No memory left\n");
			return 0;
		}
	}	
	if (s.len) {
		if (parse_phostport(tmp, &host.s, &host.len,
							&port, &proto) != 0) {
			LM_ERR("parsing of socket info <%s> failed\n", tmp);
			if (pos) pkg_free(tmp);
			return 0;
		}

		*sock = grep_sock_info(&host, (unsigned short)port,
							   (unsigned short)proto);
		if (*sock == 0) {
			LM_ERR("invalid socket <%s>\n", tmp);
			if (pos) pkg_free(tmp);
			return 0;
		}
	}
	
	if (pos) pkg_free(tmp);
	else return 1;
	
    s.s = at = pos + 1;
    if ((pos = strchr(at, '\n')) == NULL) s.len = strlen(s.s);
    else s.len = pos - s.s;

    if (s.len) {
		if (str2int(&s, flags) != 0) {
			LM_ERR("failed to decode flags <%.*s>\n", STR_FMT(&s));
			return 0;
		}
    }
    return 1;

uri_missing:
	ERR("decode_branch_info: Cannot decode branch URI.\n");
	return 0;
}
예제 #13
0
/**
 * @brief send a dmq message
 *
 * peer - the peer structure on behalf of which we are sending
 * body - the body of the message
 * node - we send the message to this node
 * resp_cback - a response callback that gets called when the transaction is complete
 */
int dmq_send_message(dmq_peer_t *peer, str *body, dmq_node_t *node,
		dmq_resp_cback_t *resp_cback, int max_forwards, str *content_type)
{
	uac_req_t uac_r;
	str str_hdr = {0, 0};
	str from = {0, 0}, to = {0, 0};
	dmq_cback_param_t *cb_param = NULL;
	int result = 0;
	int len = 0;

	if(!content_type) {
		LM_ERR("content-type is null\n");
		return -1;
	}
	/* add Max-Forwards and Content-Type headers */
	str_hdr.len = 34 + content_type->len + (CRLF_LEN * 2);
	str_hdr.s = pkg_malloc(str_hdr.len);
	if(str_hdr.s == NULL) {
		LM_ERR("no more pkg\n");
		return -1;
	}
	len += sprintf(str_hdr.s, "Max-Forwards: %d" CRLF "Content-Type: %.*s" CRLF,
			max_forwards, content_type->len, content_type->s);
	str_hdr.len = len;

	cb_param = shm_malloc(sizeof(*cb_param));
	if(cb_param == NULL) {
		LM_ERR("no more shm for building callback parameter\n");
		goto error;
	}
	memset(cb_param, 0, sizeof(*cb_param));
	cb_param->resp_cback = *resp_cback;
	cb_param->node = shm_dup_node(node);
	if(cb_param->node == NULL) {
		LM_ERR("error building callback parameter\n");
		goto error;
	}

	if(build_uri_str(&peer->peer_id, &dmq_server_uri, &from) < 0) {
		LM_ERR("error building from string [username %.*s]\n",
				STR_FMT(&peer->peer_id));
		goto error;
	}
	if(build_uri_str(&peer->peer_id, &node->uri, &to) < 0) {
		LM_ERR("error building to string\n");
		goto error;
	}

	set_uac_req(&uac_r, &dmq_request_method, &str_hdr, body, NULL,
			TMCB_LOCAL_COMPLETED, dmq_tm_callback, (void *)cb_param);
	uac_r.ssock = &dmq_server_socket;

	result = tmb.t_request(&uac_r, &to, &to, &from, NULL);
	if(result < 0) {
		LM_ERR("error in tmb.t_request_within\n");
		goto error;
	}
	pkg_free(str_hdr.s);
	pkg_free(from.s);
	pkg_free(to.s);
	return 0;
error:
	pkg_free(str_hdr.s);
	if(from.s != NULL)
		pkg_free(from.s);
	if(to.s != NULL)
		pkg_free(to.s);
	if(cb_param) {
		if(cb_param->node)
			destroy_dmq_node(cb_param->node, 1);
		shm_free(cb_param);
	}
	return -1;
}
예제 #14
0
static int parse_domain(void* param, cfg_parser_t* st, unsigned int flags)
{
	cfg_token_t t;
	int ret;
	cfg_option_t* opt;

	int type;
	struct ip_addr ip;
	unsigned int port;

	memset(&ip, 0, sizeof(struct ip_addr));

	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: TLS domain type missing\n", 
		    st->file, st->line, st->col);
		return -1;
	}

	if (t.type != CFG_TOKEN_ALPHA || 
	    ((opt = cfg_lookup_token(domain_types, &t.val)) == NULL)) {
		ERR("%s:%d:%d: Invalid TLS domain type %d:'%.*s'\n", 
		    st->file, t.start.line, t.start.col, t.type, STR_FMT(&t.val));
		return -1;
	}
	
	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: TLS domain IP address missing\n", 
		    st->file, st->line, st->col);
		return -1;
	}
	if (t.type != ':') {
		ERR("%s:%d:%d: Syntax error, ':' expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}	

	port = 0;
	if (parse_hostport(&type, &ip, &port, &t, st) < 0) return -1;

	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Closing ']' missing\n", 
		    st->file, st->line, st->col);
		return -1;
	}
	if (t.type != ']') {
		ERR("%s:%d:%d: Syntax error, ']' expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}

	if (cfg_eat_eol(st, flags)) return -1;

	if ((domain = tls_new_domain(opt->val | type, &ip, port)) == NULL) {
		ERR("%s:%d: Cannot create TLS domain structure\n", st->file, st->line);
		return -1;
	}

	ret = tls_add_domain(cfg, domain);
	if (ret < 0) {
		ERR("%s:%d: Error while creating TLS domain structure\n", st->file, 
			st->line);
		tls_free_domain(domain);
		return -1;
	} else if (ret == 1) {
		ERR("%s:%d: Duplicate TLS domain (appears earlier in the config file)\n", 
		    st->file, st->line);
		tls_free_domain(domain);
		return -1;
	}
	
	update_opt_variables();
	cfg_set_options(st, options);
	return 0;
}
예제 #15
0
static void control_ng_incoming(struct obj *obj, str *buf, const endpoint_t *sin, char *addr,
		struct udp_listener *ul)
{
	struct control_ng *c = (void *) obj;
	bencode_buffer_t bencbuf;
	bencode_item_t *dict, *resp;
	str cmd, cookie, data, reply, *to_send, callid;
	const char *errstr;
	struct iovec iov[3];
	unsigned int iovlen;
	GString *log_str;

	struct control_ng_stats* cur = get_control_ng_stats(c,&sin->address);

	str_chr_str(&data, buf, ' ');
	if (!data.s || data.s == buf->s) {
		ilog(LOG_WARNING, "Received invalid data on NG port (no cookie) from %s: "STR_FORMAT, addr, STR_FMT(buf));
		return;
	}

	bencode_buffer_init(&bencbuf);
	resp = bencode_dictionary(&bencbuf);

	cookie = *buf;
	cookie.len -= data.len;
	*data.s++ = '\0';
	data.len--;

	errstr = "Invalid data (no payload)";
	if (data.len <= 0)
		goto err_send;

	to_send = cookie_cache_lookup(&c->cookie_cache, &cookie);
	if (to_send) {
		ilog(LOG_INFO, "Detected command from %s as a duplicate", addr);
		resp = NULL;
		goto send_only;
	}

	dict = bencode_decode_expect_str(&bencbuf, &data, BENCODE_DICTIONARY);
	errstr = "Could not decode dictionary";
	if (!dict)
		goto err_send;

	bencode_dictionary_get_str(dict, "command", &cmd);
	errstr = "Dictionary contains no key \"command\"";
	if (!cmd.s)
		goto err_send;

	bencode_dictionary_get_str(dict, "call-id", &callid);
	log_info_str(&callid);

	ilog(LOG_INFO, "Received command '"STR_FORMAT"' from %s", STR_FMT(&cmd), addr);

	if (get_log_level() >= LOG_DEBUG) {
		log_str = g_string_sized_new(256);
		g_string_append_printf(log_str, "Dump for '"STR_FORMAT"' from %s: ", STR_FMT(&cmd), addr);
		pretty_print(dict, log_str);
		ilog(LOG_DEBUG, "%.*s", (int) log_str->len, log_str->str);
		g_string_free(log_str, TRUE);
	}

	errstr = NULL;
	if (!str_cmp(&cmd, "ping")) {
		bencode_dictionary_add_string(resp, "result", "pong");
		g_atomic_int_inc(&cur->ping);
	}
	else if (!str_cmp(&cmd, "offer")) {
		errstr = call_offer_ng(dict, c->callmaster, resp, addr, sin);
		g_atomic_int_inc(&cur->offer);
	}
	else if (!str_cmp(&cmd, "answer")) {
		errstr = call_answer_ng(dict, c->callmaster, resp);
		g_atomic_int_inc(&cur->answer);
	}
	else if (!str_cmp(&cmd, "delete")) {
		errstr = call_delete_ng(dict, c->callmaster, resp);
		g_atomic_int_inc(&cur->delete);
	}
예제 #16
0
static int parse_hostport(int* type, struct ip_addr* ip, unsigned int* port, 
						  cfg_token_t* token, cfg_parser_t* st)
{
	int ret;
	cfg_token_t t;
    cfg_option_t* opt;

	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Missing IP address\n", st->file, 
			token->start.line, token->start.col);
		return -1;
	}

	if (t.type == '[') {
		if (parse_ipv6(ip, &t, st) < 0) return -1;
	} else if (t.type == CFG_TOKEN_ALPHA) {
		opt = cfg_lookup_token(token_default, &t.val);
		if (opt) {
			*type = TLS_DOMAIN_DEF;
			     /* Default domain */
			return 0;
		} else {
			if (parse_ipv4(ip, &t, st) < 0) return -1;
		}
	} else {
		ERR("%s:%d:%d: Syntax error, IP address expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}
	*type = 0;

	     /* Parse port */
	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Syntax error, ':' expected\n", st->file, st->line, 
			st->col);
		return -1;
	}
	
	if (t.type != ':') {
		ERR("%s:%d:%d: Syntax error, ':' expected\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}	
	
	ret = cfg_get_token(&t, st, 0);
	if (ret < 0) return -1;
	if (ret > 0) {
		ERR("%s:%d:%d: Premature end of file, port number missing\n", 
		    st->file, t.start.line, t.start.col);
		return -1;
	}
	
	if (t.type != CFG_TOKEN_ALPHA || (str2int(&t.val, port) < 0)) {
		ERR("%s:%d:%d: Invalid port number '%.*s'\n", 
		    st->file, t.start.line, t.start.col, STR_FMT(&t.val));
		return -1;
	}		
	return 0;
}
예제 #17
0
파일: ld_cmd.c 프로젝트: 2pac/kamailio
int ld_cmd(db_cmd_t* cmd)
{
	struct ld_cmd* lcmd;
	struct ld_cfg* cfg;
	struct ld_fld* lfld;
	int i, j;

	lcmd = (struct ld_cmd*)pkg_malloc(sizeof(struct ld_cmd));
	if (lcmd == NULL) {
		ERR("ldap: No memory left\n");
		goto error;
	}
	memset(lcmd, '\0', sizeof(struct ld_cmd));
	if (db_drv_init(&lcmd->gen, ld_cmd_free) < 0) goto error;

	switch(cmd->type) {
	case DB_PUT:
	case DB_DEL:
	case DB_UPD:
		ERR("ldap: The driver does not support directory modifications yet.\n");
		goto error;
		break;

	case DB_GET:
		break;

	case DB_SQL:
		ERR("ldap: The driver does not support raw queries yet.\n");
		goto error;
	}

	cfg = ld_find_cfg(&cmd->table);
	if (cfg == NULL) {
		ERR("ldap: Cannot find configuration for '%.*s', giving up\n",
			STR_FMT(&cmd->table));
		goto error;
	}

	lcmd->base = cfg->base.s;
	lcmd->scope = cfg->scope;

	lcmd->sizelimit = cfg->sizelimit;
	if (cfg->timelimit) {
		lcmd->timelimit.tv_sec = cfg->timelimit;
		lcmd->timelimit.tv_usec = 0;
	}

	if (cfg->filter.s) {
		lcmd->filter = cfg->filter;
	}
	lcmd->chase_references = cfg->chase_references;
	lcmd->chase_referrals = cfg->chase_referrals;

	if (ld_resolve_fld(cmd->match, cfg) < 0) goto error;
	if (ld_resolve_fld(cmd->result, cfg) < 0) goto error;

	/* prepare filter for each result field */
	for(i = 0; !DB_FLD_EMPTY(cmd->result) && !DB_FLD_LAST(cmd->result[i]); i++) {
		int n;
		lfld = DB_GET_PAYLOAD(cmd->result + i);
		lfld->filter = NULL;
	
		for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
			if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0)
				n++;	
		}
		
		if (n > 0) {
			lfld->filter = pkg_malloc((n+1)*sizeof(*(lfld->filter)));
			if (!lfld->filter) return -1 /* E_OUT_OF_MEM*/;
			for(j = 0, n = 0; !DB_FLD_EMPTY(cmd->match) && !DB_FLD_LAST(cmd->match[j]); j++) {
				if (strcmp(cmd->result[i].name, cmd->match[j].name) == 0) {
					lfld->filter[n] = cmd->match+j;
					n++;
				}
			}
			lfld->filter[n] = NULL;
		}
	}
	if (build_result_array(&lcmd->result, cmd) < 0) goto error;

	DB_SET_PAYLOAD(cmd, lcmd);
	return 0;

 error:
	if (lcmd) {
		DB_SET_PAYLOAD(cmd, NULL);
		db_drv_free(&lcmd->gen);
		if (lcmd->result) pkg_free(lcmd->result);
		pkg_free(lcmd);
	}
	return -1;
}
예제 #18
0
    int
sca_create_canonical_aor_for_ua( sip_msg_t *msg, str *c_aor, int ua_opts )
{
    struct to_body	*tf = NULL;
    sip_uri_t		c_uri;
    str			tf_aor = STR_NULL;
    str			contact_uri = STR_NULL;
    int			rc = -1;

    assert( msg != NULL );
    assert( c_aor != NULL );

    memset( c_aor, 0, sizeof( str ));

    if (( ua_opts & SCA_AOR_TYPE_AUTO )) {
	if ( msg->first_line.type == SIP_REQUEST ) {
	    ua_opts = SCA_AOR_TYPE_UAC;
	} else {
	    ua_opts = SCA_AOR_TYPE_UAS;
	}
    }

    if (( ua_opts & SCA_AOR_TYPE_UAC )) {
	if ( sca_get_msg_from_header( msg, &tf ) < 0 ) {
	    LM_ERR( "sca_create_canonical_aor: failed to get From header" );
	    goto done;
	}
    } else {
	if ( sca_get_msg_to_header( msg, &tf ) < 0 ) {
	    LM_ERR( "sca_create_canonical_aor: failed to get To header" );
	    goto done;
	}
    }

    if ( sca_uri_extract_aor( &tf->uri, &tf_aor ) < 0 ) {
	LM_ERR( "sca_create_canonical_aor: failed to extract AoR from "
		"URI <%.*s>", STR_FMT( &tf->uri ));
	goto done;
    }

    memset( &c_uri, 0, sizeof( sip_uri_t ));
    if (( rc = sca_get_msg_contact_uri( msg, &contact_uri )) < 0 ) {
	LM_ERR( "sca_create_canonical_aor: failed to get contact URI from "
		"Contact <%.*s>", STR_FMT( &msg->contact->body ));
	goto done;
    }
    if ( rc > 0 ) {
	if ( parse_uri( contact_uri.s, contact_uri.len, &c_uri ) < 0 ) {
	    LM_ERR( "sca_create_canonical_aor: failed to parse Contact URI "
		    "<%.*s>", STR_FMT( &contact_uri ));
	    rc = -1;
	    goto done;
	}
    }

    if ( SCA_STR_EMPTY( &c_uri.user ) ||
	    SCA_STR_EQ( &c_uri.user, &tf->parsed_uri.user )) {
	/* empty contact header or Contact user matches To/From AoR */
	c_aor->s = (char *)pkg_malloc( tf_aor.len );
	c_aor->len = tf_aor.len;
	memcpy( c_aor->s, tf_aor.s, tf_aor.len );
    } else {
	/* Contact user and To/From user mismatch */
	if ( sca_aor_create_from_info( c_aor, c_uri.type,
		&c_uri.user, &tf->parsed_uri.host,
		&tf->parsed_uri.port ) < 0 ) {
	    LM_ERR( "sca_create_canonical_aor: failed to create AoR from "
		    "Contact <%.*s> and URI <%.*s>",
		    STR_FMT( &contact_uri ), STR_FMT( &tf_aor ));
	    goto done;
	}
    }

    rc = 1;

done:
    return( rc );
}
예제 #19
0
/*
 * The function creates an ACK to 200 OK. Route set will be created
 * and parsed and the dst parameter will contain the destination to which
 * the request should be send. The function is used by tm when it
 * generates local ACK to 200 OK (on behalf of applications using uac)
 */
char *build_dlg_ack(struct sip_msg* rpl, struct cell *Trans,
					unsigned int branch, str *hdrs, str *body,
					unsigned int *len, struct dest_info* dst)
{
	char *req_buf, *p, *via;
	unsigned int via_len;
	char branch_buf[MAX_BRANCH_PARAM_LEN];
	int branch_len;
	str branch_str;
	struct hostport hp;
	struct rte* list;
	str contact, ruri, *cont;
	str next_hop;
	str body_len;
	str _to, *to = &_to;
#ifdef USE_DNS_FAILOVER
	struct dns_srv_handle dns_h;
#endif
#ifdef WITH_AS_SUPPORT
	/* With AS support, TM allows for external modules to generate building of
	 * the ACK; in this case, the ACK's retransmission buffer is built once
	 * and kept in memory (to help when retransmitted 2xx are received and ACK
	 * must be resent).
	 * Allocation of the string raw buffer that holds the ACK is piggy-backed
	 * with allocation of the retransmission buffer (since both have the same
	 * life-cycle): both the string buffer and retransm. buffer are placed
	 * into the same allocated chunk of memory (retr. buffer first, string
	 * buffer follows).In this case, the 'len' param is used as in-out
	 * parameter: 'in' to give the extra space needed by the retr. buffer,
	 * 'out' to return the lenght of the allocated string buffer.
	 */
	unsigned offset = *len;
#endif

	if (parse_headers(rpl, HDR_EOH_F, 0) == -1 || !rpl->to) {
		LM_ERR("Error while parsing headers.\n");
		return 0;
	} else {
		_to.s = rpl->to->name.s;
		_to.len = rpl->to->len;
	}

	if (get_contact_uri(rpl, &contact) < 0) {
		return 0;
	}

	if (eval_uac_routing(rpl, &Trans->uac[branch].request, &contact,
			&list, &ruri, &next_hop) < 0) {
		LM_ERR("failed to evaluate routing elements.\n");
		return 0;
	}
	LM_DBG("ACK RURI: `%.*s', NH: `%.*s'.\n", STR_FMT(&ruri),
			STR_FMT(&next_hop));

	if ((contact.s != ruri.s) || (contact.len != ruri.len)) {
		/* contact != ruri means that the next
		 * hop is a strict router, cont will be non-zero
		 * and print_routeset will append it at the end
		 * of the route set
		 */
		cont = &contact;
	} else {
		/* Next hop is a loose router, nothing to append */
		cont = 0;
	}

	/* method, separators, version: "ACK sip:[email protected] SIP/2.0" */
	*len = SIP_VERSION_LEN + ACK_LEN + 2 /* spaces */ + CRLF_LEN;
	*len += ruri.len;

	/* dst */
	switch(cfg_get(tm, tm_cfg, local_ack_mode)){
		case 1:
			/* send the local 200 ack to the same dst as the corresp. invite*/
			*dst=Trans->uac[branch].request.dst;
			break;
		case 2:
			/* send the local 200 ack to the same dst as the 200 reply source*/
			init_dst_from_rcv(dst, &rpl->rcv);
			dst->send_flags=rpl->fwd_send_flags;
			break;
		case 0:
		default:
			/* rfc conformant behaviour: use the next_hop determined from the
			 * contact and the route set */
#ifdef USE_DNS_FAILOVER
		if (cfg_get(core, core_cfg, use_dns_failover)){
			dns_srv_handle_init(&dns_h);
			if ((uri2dst(&dns_h , dst, rpl, &next_hop, PROTO_NONE)==0) ||
					(dst->send_sock==0)){
				dns_srv_handle_put(&dns_h);
				LM_ERR("no socket found\n");
				goto error;
			}
			dns_srv_handle_put(&dns_h); /* not needed any more */
		}else{
			if ((uri2dst(0 , dst, rpl, &next_hop, PROTO_NONE)==0) ||
					(dst->send_sock==0)){
				LM_ERR("no socket found\n");
				goto error;
			}
		}
#else /* USE_DNS_FAILOVER */
		if ( (uri2dst( dst, rpl, &next_hop, PROTO_NONE)==0) ||
				(dst->send_sock==0)){
			LM_ERR("no socket found\n");
			goto error;
		}
#endif /* USE_DNS_FAILOVER */
		break;
	}

	/* via */
	if (!t_calc_branch(Trans,  branch, branch_buf, &branch_len)) goto error;
	branch_str.s = branch_buf;
	branch_str.len = branch_len;
	set_hostport(&hp, 0);
	via = via_builder(&via_len, NULL, dst, &branch_str, 0, &hp);
	if (!via) {
		LM_ERR("No via header got from builder\n");
		goto error;
	}
	*len+= via_len;

	/* headers */
	*len += Trans->from.len + Trans->callid.len + to->len + Trans->cseq_n.len + 1 + ACK_LEN + CRLF_LEN;

	/* copy'n'paste Route headers */

	*len += calc_routeset_len(list, cont);

	/* User Agent */
	if (server_signature) *len += user_agent_hdr.len + CRLF_LEN;
	/* extra headers */
	if (hdrs)
		*len += hdrs->len;
	/* body */
	if (body) {
		body_len.s = int2str(body->len, &body_len.len);
		*len += body->len;
	} else {
		body_len.len = 0;
		body_len.s = NULL; /*4gcc*/
		*len += 1; /* for the (Cont-Len:) `0' */
	}
	/* Content Length, EoM */
	*len += CONTENT_LENGTH_LEN + body_len.len + CRLF_LEN + CRLF_LEN;

#if WITH_AS_SUPPORT
	req_buf = shm_malloc(offset + *len + 1);
	req_buf += offset;
#else
	req_buf = shm_malloc(*len + 1);
#endif
	if (!req_buf) {
		LM_ERR("Cannot allocate memory (%u+1)\n", *len);
		goto error01;
	}
	p = req_buf;

	append_str( p, ACK, ACK_LEN );
	append_str( p, " ", 1 );
	append_str(p, ruri.s, ruri.len);
	append_str( p, " " SIP_VERSION CRLF, 1 + SIP_VERSION_LEN + CRLF_LEN);

	/* insert our via */
	append_str(p, via, via_len);

	/*other headers*/
	append_str(p, Trans->from.s, Trans->from.len);
	append_str(p, Trans->callid.s, Trans->callid.len);
	append_str(p, to->s, to->len);

	append_str(p, Trans->cseq_n.s, Trans->cseq_n.len);
	append_str( p, " ", 1 );
	append_str( p, ACK, ACK_LEN);
	append_str(p, CRLF, CRLF_LEN);

	/* Routeset */
	p = print_rs(p, list, cont);

	/* User Agent header */
	if (server_signature) {
		append_str(p, user_agent_hdr.s, user_agent_hdr.len);
		append_str(p, CRLF, CRLF_LEN);
	}

	/* extra headers */
	if (hdrs)
		append_str(p, hdrs->s, hdrs->len);

	/* Content Length, EoH, (body) */
	if (body) {
		append_str(p, CONTENT_LENGTH, CONTENT_LENGTH_LEN);
		append_str(p, body_len.s, body_len.len);
		append_str(p, /*end crr. header*/CRLF /*EoH*/CRLF, CRLF_LEN +
				CRLF_LEN);
		append_str(p, body->s, body->len);
	} else {
		append_str(p, CONTENT_LENGTH "0" CRLF CRLF,
				CONTENT_LENGTH_LEN + 1 + CRLF_LEN + CRLF_LEN);
	}

	/* EoM */
	*p = 0;

	pkg_free(via);
	free_rte_list(list);
	return req_buf;

error01:
	pkg_free(via);
error:
	free_rte_list(list);
	return 0;
}
예제 #20
0
static void call_ng_process_flags(struct sdp_ng_flags *out, bencode_item_t *input) {
	bencode_item_t *list, *it;
	int diridx;
	str s;

	ZERO(*out);

	if ((list = bencode_dictionary_get_expect(input, "flags", BENCODE_LIST))) {
		for (it = list->child; it; it = it->sibling) {
			str_hyphenate(it);
			if (!bencode_strcmp(it, "trust-address"))
				out->trust_address = 1;
			else if (!bencode_strcmp(it, "asymmetric"))
				out->asymmetric = 1;
			else if (!bencode_strcmp(it, "strict-source"))
				out->strict_source = 1;
			else if (!bencode_strcmp(it, "media-handover"))
				out->media_handover = 1;
			else
				ilog(LOG_WARN, "Unknown flag encountered: '"BENCODE_FORMAT"'",
						BENCODE_FMT(it));
		}
	}

	if ((list = bencode_dictionary_get_expect(input, "replace", BENCODE_LIST))) {
		for (it = list->child; it; it = it->sibling) {
			str_hyphenate(it);
			if (!bencode_strcmp(it, "origin"))
				out->replace_origin = 1;
			else if (!bencode_strcmp(it, "session-connection"))
				out->replace_sess_conn = 1;
			else
				ilog(LOG_WARN, "Unknown 'replace' flag encountered: '"BENCODE_FORMAT"'",
						BENCODE_FMT(it));
		}
	}

	diridx = 0;
	if ((list = bencode_dictionary_get_expect(input, "direction", BENCODE_LIST))) {
		for (it = list->child; it && diridx < 2; it = it->sibling)
			bencode_get_str(it, &out->direction[diridx++]);
	}

	list = bencode_dictionary_get_expect(input, "received from", BENCODE_LIST);
	if (!list)
		list = bencode_dictionary_get_expect(input, "received-from", BENCODE_LIST);
	if (list && (it = list->child)) {
		bencode_get_str(it, &out->received_from_family);
		bencode_get_str(it->sibling, &out->received_from_address);
	}

	if (bencode_dictionary_get_str(input, "ICE", &s)) {
		if (!str_cmp(&s, "remove"))
			out->ice_remove = 1;
		else if (!str_cmp(&s, "force"))
			out->ice_force = 1;
		else if (!str_cmp(&s, "force_relay") || !str_cmp(&s, "force-relay"))
			out->ice_force_relay = 1;
		else
			ilog(LOG_WARN, "Unknown 'ICE' flag encountered: '"STR_FORMAT"'",
					STR_FMT(&s));
	}

	if ((list = bencode_dictionary_get_expect(input, "rtcp-mux", BENCODE_LIST))) {
		for (it = list->child; it; it = it->sibling) {
			if (!bencode_strcmp(it, "offer"))
				out->rtcp_mux_offer = 1;
			else if (!bencode_strcmp(it, "demux"))
				out->rtcp_mux_demux = 1;
			else if (!bencode_strcmp(it, "accept"))
				out->rtcp_mux_accept = 1;
			else if (!bencode_strcmp(it, "reject"))
				out->rtcp_mux_reject = 1;
			else
				ilog(LOG_WARN, "Unknown 'rtcp-mux' flag encountered: '"BENCODE_FORMAT"'",
						BENCODE_FMT(it));
		}
	}

	bencode_get_alt(input, "transport-protocol", "transport protocol", &out->transport_protocol_str);
	out->transport_protocol = transport_protocol(&out->transport_protocol_str);
	bencode_get_alt(input, "media-address", "media address", &out->media_address);
	if (bencode_get_alt(input, "address-family", "address family", &out->address_family_str))
		out->address_family = address_family(&out->address_family_str);
	out->tos = bencode_dictionary_get_integer(input, "TOS", 256);
}
예제 #21
0
/**
 * Evaluate if next hop is a strict or loose router, by looking at the
 * retr. buffer of the original INVITE.
 * Assumes:
 * 	orig_inv is a parsed SIP message;
 * 	rtset is not NULL.
 * @return:
 * 	F_RB_NH_LOOSE : next hop was loose router;
 * 	F_RB_NH_STRICT: nh is strict;
 * 	0 on error.
 */
static unsigned long nhop_type(sip_msg_t *orig_inv, rte_t *rtset,
		const struct dest_info *dst_inv, str *contact)
{
	struct sip_uri puri, topr_uri, lastr_uri, inv_ruri, cont_uri;
	struct ip_addr *uri_ia;
	union sockaddr_union uri_sau;
	unsigned int uri_port, dst_port, inv_port, cont_port, lastr_port;
	rte_t *last_r;
#ifdef TM_LOC_ACK_DO_REV_DNS
	struct ip_addr ia;
	struct hostent *he;
	char **alias;
#endif

#define PARSE_URI(_str_, _uri_) \
	do { \
		/* parse_uri() 0z the puri */ \
		if (parse_uri((_str_)->s, \
				(_str_)->len, _uri_) < 0) { \
			LM_ERR("failed to parse route body '%.*s'.\n", STR_FMT(_str_)); \
			return 0; \
		} \
	} while (0)

#define HAS_LR(_rte_) \
	({ \
		PARSE_URI(&(_rte_)->ptr->nameaddr.uri, &puri); \
		puri.lr.s; \
	})

#define URI_PORT(_puri_, _port) \
	do { \
		if (! (_port = uri2port(_puri_))) \
			return 0; \
	} while (0)

	/* examine the easy/fast & positive cases foremost */

	/* [1] check if 1st route lacks ;lr */
	LM_DBG("checking lack of ';lr' in 1st route.\n");
	if (! HAS_LR(rtset))
		return F_RB_NH_STRICT;
	topr_uri = puri; /* save 1st route's URI */

	/* [2] check if last route shows ;lr */
	LM_DBG("checking presence of ';lr' in last route.\n");
	for (last_r = rtset; last_r->next; last_r = last_r->next)
		/* scroll down to last route */
		;
	if (HAS_LR(last_r))
		return F_RB_NH_LOOSE;

	/* [3] 1st route has ;lr -> check if the destination of original INV
	 * equals the address provided by this route; if does -> loose */
	LM_DBG("checking INVITE's destination against its first route.\n");
	URI_PORT(&topr_uri, uri_port);
	if (! (dst_port = su_getport(&dst_inv->to)))
		return 0; /* not really expected */
	if (dst_port != uri_port)
		return F_RB_NH_STRICT;
	/* if 1st route contains an IP address, comparing it against .dst */
	if ((uri_ia = str2ip(&topr_uri.host))
			|| (uri_ia = str2ip6(&topr_uri.host))
			) {
		/* we have an IP address in route -> comparison can go swiftly */
		if (init_su(&uri_sau, uri_ia, uri_port) < 0)
			return 0; /* not really expected */
		if (su_cmp(&uri_sau, &dst_inv->to))
			/* ;lr and sent there */
			return F_RB_NH_LOOSE;
		else
			/* ;lr and NOT sent there (probably sent to RURI address) */
			return F_RB_NH_STRICT;
	} else {
		/*if 1st route contains a name, rev resolve the .dst and compare*/
		LM_INFO("Failed to decode string '%.*s' in route set element as IP"
				" address. Trying name resolution.\n",STR_FMT(&topr_uri.host));

	/* TODO: alternatively, rev name and compare against dest. IP.  */
#ifdef TM_LOC_ACK_DO_REV_DNS
		ia.af = 0;
		su2ip_addr(&ia, (void *)&dst_inv->to);
		if (! ia.af)
			return 0; /* not really expected */
		if ((he = rev_resolvehost(&ia))) {
			if ((strlen(he->h_name) == topr_uri.host.len) &&
					(memcmp(he->h_name, topr_uri.host.s,
							topr_uri.host.len) == 0))
				return F_RB_NH_LOOSE;
			for (alias = he->h_aliases; *alias; alias ++)
				if ((strlen(*alias) == topr_uri.host.len) &&
						(memcmp(*alias, topr_uri.host.s,
								topr_uri.host.len) == 0))
					return F_RB_NH_LOOSE;
			return F_RB_NH_STRICT;
		} else {
			LM_INFO("failed to resolve address '%s' to a name.\n",
					ip_addr2a(&ia));
		}
#endif
	}

	LM_WARN("failed to establish with certainty the type of next hop;"
			" trying an educated guess.\n");

	/* [4] compare (possibly updated) remote target to original RURI; if
	 * equal, a strict router's address wasn't filled in as RURI -> loose */
	LM_DBG("checking remote target against INVITE's RURI.\n");
	PARSE_URI(contact, &cont_uri);
	PARSE_URI(GET_RURI(orig_inv), &inv_ruri);
	URI_PORT(&cont_uri, cont_port);
	URI_PORT(&inv_ruri, inv_port);
	if ((cont_port == inv_port) && (cont_uri.host.len == inv_ruri.host.len) &&
			(memcmp(cont_uri.host.s, inv_ruri.host.s, cont_uri.host.len) == 0))
		return F_RB_NH_LOOSE;

	/* [5] compare (possibly updated) remote target to last route; if equal,
	 * strict router's address might have been filled as RURI and remote
	 * target appended to route set -> strict */
	LM_DBG("checking remote target against INVITE's last route.\n");
	PARSE_URI(&last_r->ptr->nameaddr.uri, &lastr_uri);
	URI_PORT(&lastr_uri, lastr_port);
	if ((cont_port == lastr_port) &&
			(cont_uri.host.len == lastr_uri.host.len) &&
			(memcmp(cont_uri.host.s, lastr_uri.host.s,
					lastr_uri.host.len) == 0))
		return F_RB_NH_STRICT;

	LM_WARN("failed to establish the type of next hop;"
			" assuming loose router.\n");
	return F_RB_NH_LOOSE;

#undef PARSE_URI
#undef HAS_LR
#undef URI_PORT
}
예제 #22
0
/*
 * send a call-info NOTIFY to all subscribers to a given SCA AoR.
 */
int sca_notify_call_info_subscribers(sca_mod *scam, str *subscription_aor)
{
	sca_hash_slot *slot;
	sca_hash_entry *e;
	sca_subscription *sub;
	str headers = STR_NULL;
	str hash_key = STR_NULL;
	char hdrbuf[SCA_HEADERS_MAX_LEN];
	char keybuf[512];
	char *event_name;
	int slot_idx;
	int rc = -1;

	assert(scam->subscriptions != NULL);
	assert(!SCA_STR_EMPTY(subscription_aor));

	LM_DBG("Notifying ALL subscribers of AOR %.*s due to a SUBSCRIBTION request\n",
			STR_FMT(subscription_aor));

	event_name = sca_event_name_from_type(SCA_EVENT_TYPE_CALL_INFO);
	if (subscription_aor->len + strlen(event_name) >= sizeof(keybuf)) {
		LM_ERR("Hash key %.*s + %s is too long\n",
				STR_FMT(subscription_aor), event_name);
		return (-1);
	}
	hash_key.s = keybuf;
	SCA_STR_COPY(&hash_key, subscription_aor);
	SCA_STR_APPEND_CSTR(&hash_key, event_name);

	slot_idx = sca_hash_table_index_for_key(scam->subscriptions, &hash_key);
	slot = sca_hash_table_slot_for_index(scam->subscriptions, slot_idx);

	sca_hash_table_lock_index(scam->subscriptions, slot_idx);

	for (e = slot->entries; e != NULL; e = e->next) {
		sub = (sca_subscription *) e->value;
		if (!SCA_STR_EQ(subscription_aor, &sub->target_aor)) {
			continue;
		}

		if (headers.len == 0) {
			headers.s = hdrbuf;

			if (sca_notify_build_headers_from_info(&headers, sizeof(hdrbuf),
					scam, sub, SCA_CALL_INFO_APPEARANCE_INDEX_ANY) < 0) {
				LM_ERR("Failed to build NOTIFY headers\n");
				goto done;
			}
		}

		// XXX would like this to be wrapped in one location
		sub->dialog.notify_cseq += 1;

		if (sca_notify_subscriber_internal(scam, sub, &headers) < 0) {
			goto done;
		}
	}
	rc = 1;

	done:
	sca_hash_table_unlock_index(scam->subscriptions, slot_idx);

	return (rc);
}
예제 #23
0
/**
 * extract the node list from the body of a notification request SIP message
 * the SIP request will look something like:
 * 	KDMQ sip:10.0.0.0:5062
 * 	To: ...
 * 	From: ...
 * 	Max-Forwards: ...
 * 	Content-Length: 22
 * 	
 * 	sip:host1:port1;param1=value1
 * 	sip:host2:port2;param2=value2
 * 	...
 */
int extract_node_list(dmq_node_list_t* update_list, struct sip_msg* msg)
{
	int content_length, total_nodes = 0;
	str body;
	str tmp_uri;
	dmq_node_t *cur = NULL;
	dmq_node_t *ret, *find;
	char *tmp, *end, *match;

	if(!msg->content_length && (parse_headers(msg,HDR_CONTENTLENGTH_F,0)<0 || !msg->content_length)) {
		LM_ERR("no content length header found\n");
		return -1;
	}
	content_length = get_content_length(msg);
	if(!content_length) {
		LM_DBG("content length is 0\n");
		return total_nodes;
	}
	body.s = get_body(msg);
	body.len = content_length;
	tmp = body.s;
	end = body.s + body.len;
	
	/* acquire big list lock */
	lock_get(&update_list->lock);
	while(tmp < end) {
		match = q_memchr(tmp, '\n', end - tmp);
		if(match) {
			match++;
		} else {
			/* for the last line - take all of it */
			match = end;
		}
		/* create the orig_uri from the parsed uri line and trim it */
		tmp_uri.s = tmp;
		tmp_uri.len = match - tmp - 1;
		tmp = match;
		/* trim the \r, \n and \0's */
		trim_r(tmp_uri);
		find = build_dmq_node(&tmp_uri, 0);
		if(find==NULL)
			return -1;
		ret = find_dmq_node(update_list, find);
		if (!ret) {
			LM_DBG("found new node %.*s\n", STR_FMT(&tmp_uri));
			cur = build_dmq_node(&tmp_uri, 1);
			if(!cur) {
				LM_ERR("error creating new dmq node\n");
				goto error;
			}
			cur->next = update_list->nodes;
			update_list->nodes = cur;
			update_list->count++;
			total_nodes++;
		} else if (find->params && ret->status != find->status) {
			LM_DBG("updating status on %.*s from %d to %d\n",
				STR_FMT(&tmp_uri), ret->status, find->status);
			ret->status = find->status;
			total_nodes++;
		}
		destroy_dmq_node(find, 0);
	}

	/* release big list lock */
	lock_release(&update_list->lock);
	return total_nodes;
error:
	lock_release(&update_list->lock);
	return -1;
}
예제 #24
0
int pv_xbuff_parse_name(pv_spec_t *sp, str *in)
{
	char *p;
	str idx;
	str name;
	str attr;
	int l;

	if (in->s == NULL || in->len <= 0)
		return -1;

	p = in->s;

	name.s = p;

	while (is_in_str(p, in)) {
		if (*p == '[' || *p== '=')
			break;
		if (!is_pv_xbuff_valid_char(*p)) {
			l = p-in->s;
			LM_ERR("invalid character in var name %.*s at %d\n",STR_FMT(in),l);
			goto error;
		}
		p++;
	}

	/* from in->s to p */
	name.len = p - in->s;

	if (pv_parse_avp_name(sp,&name))
		goto error;

	if (is_in_str(p,in) && *p =='[')
	{
		idx.s=++p;

		while (is_in_str(p,in)) {
			if (*p == ']' || *p == '=')
				break;
			p++;
		}

		if (is_in_str(p,in) && *p==']') {
			idx.len = p - idx.s;

			if (pv_parse_index(sp,&idx))
				goto error;
		}
		p++;
	} else {
		xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_NO_IDX);
	}

	if (is_in_str(p,in) && *p =='=')
	{
		p++;

		if (!is_in_str(p,in) || *p!='>') {
			l = p-in->s;
			LM_ERR("invalid operator (expected =>) for accessing attribute in token %.*s at position %d\n",STR_FMT(in),l);
			goto error;
		}

		attr.s = ++p;

		while (is_in_str(p,in)) {
			if (!is_pv_xbuff_valid_char(*p)) {
				l = p-in->s;
				LM_ERR("invalid character in attribute name in token %.*s at %d\n",STR_FMT(in),l);
				goto error;
			}
			p++;
		}

		attr.len = p - attr.s;

		if (attr.len > 0 ) {

			if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_TYPE))) {
				xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_ATTR_TYPE);
			} else if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_FORMAT))) {
				xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_ATTR_FORMAT);
			} else if (STR_EQ(attr,xbuff_attr_name(XBUFF_ATTR_LENGTH))) {
				xbuff_set_attr_flag(sp->pvp.pvi.type,XBUFF_ATTR_LENGTH);
			} else {
				LM_ERR("unknown attribute %.*s\n",STR_FMT(&attr));
				goto error;
			}

			if (sp->pvp.pvi.type & PV_IDX_ALL) {
				LM_ERR("index [*] (all) isn't compatible with attribute %.*s\n",STR_FMT(&attr));
				goto error;
			}
		}
	}

	if (p < in->s + in->len) {
		l = p-in->s;
		LM_ERR("unexpected token in %.*s at %d\n",STR_FMT(in),l);
		goto error;
	}

	return 0;

error:

	return -1;
}
예제 #25
0
/*
 * Function returns always success - we uses EPMD for transport
 */
int erl_rpc_send(erl_rpc_ctx_t *ctx, int depth)
{
	if (ctx->response_sent) return 0;
	ctx->response_sent = 1;
	erl_rpc_ctx_t *handler;
	erl_rpc_param_t *fault = *(ctx->fault_p);

	if (fault)
	{
		LM_ERR("fault: %d %.*s\n",fault->type, STR_FMT(&fault->value.S));
		/* restore clear point */
		ctx->response->index = ctx->response_index;

		/* {error,{struct,[ {"code", 400}, {"error","Error message"}]}}*/
		if (ei_x_encode_tuple_header(ctx->response,1)) goto error;	/* {error,{_,_}} */
		if (rpc_reply_with_struct && ei_x_encode_atom(ctx->response,"struct")) goto error;	/* {error,{struct,_}} */
		if (ei_x_encode_list_header(ctx->response,2)) goto error;	/* {error,{struct,[_,_]}} */
		if (ei_x_encode_tuple_header(ctx->response,2)) goto error;	/* {error,{struct,[{_,_},_]}} */
		if (ei_x_encode_atom(ctx->response,"code")) goto error;		/* {error,{struct,[{code,_},_]}} */
		if (ei_x_encode_long(ctx->response,fault->type)) goto error;/* {error,{struct,[{code,400},_]}} */
		if (ei_x_encode_tuple_header(ctx->response,2)) goto error;	/* {error,{struct,[{code,400},{_,_}]}} */
		if (ei_x_encode_binary(ctx->response,"error",sizeof("error")-1)) goto error;	/* {error,{struct,[{code,400},{<<"error">>,_}]}} */
		if (ei_x_encode_binary(ctx->response,(void*)fault->value.S.s,fault->value.S.len)) /* {error,{struct,[{code,400},{<<"error">>,<<Msg>>}]}} */
			goto error;
		if (ei_x_encode_empty_list(ctx->response)) goto error;
	}
	else if (ctx->reply_params)
	{
		while(ctx->reply_params)
		{
			if (ctx->reply_params->member_name)
			{
				/* {"member_name", _} */
				if (ei_x_encode_tuple_header(ctx->response,2)) goto error;
				if (ei_x_encode_binary(ctx->response,ctx->reply_params->member_name, strlen(ctx->reply_params->member_name)))
					goto error;
			}
			/* {"member_name", MemberValue} */
			switch (ctx->reply_params->type) {
				case ERL_INTEGER_EXT:
					if(ei_x_encode_long(ctx->response,ctx->reply_params->value.n)) goto error;
					break;
				case ERL_FLOAT_EXT:
					if(ei_x_encode_double(ctx->response,ctx->reply_params->value.d)) goto error;
					break;
				case ERL_STRING_EXT:
					if(ei_x_encode_binary(ctx->response,ctx->reply_params->value.S.s,ctx->reply_params->value.S.len)) goto error;
					break;
				case ERL_SMALL_TUPLE_EXT: /* add as {struct,list(no_params)} */
					handler = (erl_rpc_ctx_t*)ctx->reply_params->value.handler;
					if (ei_x_encode_tuple_header(ctx->response,1)) goto error;
					if (rpc_reply_with_struct && ei_x_encode_atom(ctx->response,"struct")) goto error;
					if (ei_x_encode_list_header(ctx->response,handler->no_params)) goto error;
					if (erl_rpc_send(handler, depth++)) goto error;
					if (ei_x_encode_empty_list(ctx->response)) goto error;
					break;
				case ERL_LIST_EXT: /* add as [list(no_params)] */
					handler = (erl_rpc_ctx_t*)ctx->reply_params->value.handler;
					if (ei_x_encode_list_header(ctx->response,handler->no_params)) goto error;
					if (erl_rpc_send(handler, depth++)) goto error;
					if (handler->no_params)
						if (ei_x_encode_empty_list(ctx->response)) goto error;
					break;
				default:
					LM_ERR("Unknown type '%c' for encoding RPC reply\n",ctx->reply_params->type);
					break;
			}
			ctx->reply_params=ctx->reply_params->next;
		}
	}
	else if (!depth)
	{
		/* restore start point */
		LM_WARN("encode empty response -> ok");
		ctx->response->index = ctx->response_index;
		if (ei_x_encode_atom(ctx->response,"ok")) goto error;
	}

	return 0;

error:
	LM_ERR("error while encoding response\n");
	return -1;
}
예제 #26
0
static int __ensure_codec_handler(struct media_player *mp, AVStream *avs) {
	if (mp->handler)
		return 0;

	// synthesise rtp payload type
	struct rtp_payload_type src_pt = { .payload_type = -1 };
	// src_pt.codec_def = codec_find_by_av(avs->codec->codec_id);  `codec` is deprecated
	src_pt.codec_def = codec_find_by_av(avs->CODECPAR->codec_id);
	if (!src_pt.codec_def) {
		ilog(LOG_ERR, "Attempting to play media from an unsupported file format/codec");
		return -1;
	}
	src_pt.encoding = src_pt.codec_def->rtpname_str;
	src_pt.channels = avs->CODECPAR->channels;
	src_pt.clock_rate = avs->CODECPAR->sample_rate;
	codec_init_payload_type(&src_pt, mp->media);

	// find suitable output payload type
	struct rtp_payload_type *dst_pt;
	for (GList *l = mp->media->codecs_prefs_send.head; l; l = l->next) {
		dst_pt = l->data;
		if (dst_pt->codec_def && !dst_pt->codec_def->supplemental)
			goto found;
	}
	dst_pt = NULL;
found:
	if (!dst_pt) {
		ilog(LOG_ERR, "No supported output codec found in SDP");
		return -1;
	}
	ilog(LOG_DEBUG, "Output codec for media playback is " STR_FORMAT,
			STR_FMT(&dst_pt->encoding_with_params));

	// if we played anything before, scale our sync TS according to the time
	// that has passed
	if (mp->sync_ts_tv.tv_sec) {
		long long ts_diff_us = timeval_diff(&rtpe_now, &mp->sync_ts_tv);
		mp->sync_ts += ts_diff_us * dst_pt->clock_rate / 1000000 / dst_pt->codec_def->clockrate_mult;
	}

	mp->handler = codec_handler_make_playback(&src_pt, dst_pt, mp->sync_ts);
	if (!mp->handler)
		return -1;

	mp->duration = avs->duration * 1000 * avs->time_base.num / avs->time_base.den;

	return 0;
}


// appropriate lock must be held
static void media_player_read_packet(struct media_player *mp) {
	if (!mp->fmtctx)
		return;

	int ret = av_read_frame(mp->fmtctx, &mp->pkt);
	if (ret < 0) {
		if (ret == AVERROR_EOF) {
			ilog(LOG_DEBUG, "EOF reading from media stream");
			return;
		}
		ilog(LOG_ERR, "Error while reading from media stream");
		return;
	}

	if (!mp->fmtctx->streams) {
		ilog(LOG_ERR, "No AVStream present in format context");
		goto out;
	}

	AVStream *avs = mp->fmtctx->streams[0];
	if (!avs) {
		ilog(LOG_ERR, "No AVStream present in format context");
		goto out;
	}

	if (__ensure_codec_handler(mp, avs))
		goto out;

	// scale pts and duration according to sample rate

	long long duration_scaled = mp->pkt.duration * avs->CODECPAR->sample_rate
		* avs->time_base.num / avs->time_base.den;
	unsigned long long pts_scaled = mp->pkt.pts * avs->CODECPAR->sample_rate
		* avs->time_base.num / avs->time_base.den;

	long long us_dur = mp->pkt.duration * 1000000LL * avs->time_base.num / avs->time_base.den;
	ilog(LOG_DEBUG, "read media packet: pts %llu duration %lli (scaled %llu/%lli, %lli us), "
			"sample rate %i, time_base %i/%i",
			(unsigned long long) mp->pkt.pts,
			(long long) mp->pkt.duration,
			pts_scaled,
			duration_scaled,
			us_dur,
			avs->CODECPAR->sample_rate,
			avs->time_base.num, avs->time_base.den);

	// synthesise fake RTP header and media_packet context

	struct rtp_header rtp = {
		.timestamp = pts_scaled, // taken verbatim by handler_func_playback w/o byte swap
		.seq_num = htons(mp->seq),
	};
	struct media_packet packet = {
		.tv = rtpe_now,
		.call = mp->call,
		.media = mp->media,
		.rtp = &rtp,
		.ssrc_out = mp->ssrc_out,
	};
	str_init_len(&packet.raw, (char *) mp->pkt.data, mp->pkt.size);
	packet.payload = packet.raw;

	mp->handler->func(mp->handler, &packet);

	// as this is timing sensitive and we may have spent some time decoding,
	// update our global "now" timestamp
	gettimeofday(&rtpe_now, NULL);

	// keep track of RTP timestamps and real clock. look at the last packet we received
	// and update our sync TS.
	if (packet.packets_out.head) {
		struct codec_packet *p = packet.packets_out.head->data;
		if (p->rtp) {
			mp->sync_ts = ntohl(p->rtp->timestamp);
			mp->sync_ts_tv = p->to_send;
		}
	}

	media_packet_encrypt(mp->crypt_handler->out->rtp_crypt, mp->sink, &packet);

	mutex_lock(&mp->sink->out_lock);
	if (media_socket_dequeue(&packet, mp->sink))
		ilog(LOG_ERR, "Error sending playback media to RTP sink");
	mutex_unlock(&mp->sink->out_lock);

	timeval_add_usec(&mp->next_run, us_dur);
	timerthread_obj_schedule_abs(&mp->tt_obj, &mp->next_run);

out:
	av_packet_unref(&mp->pkt);
}


// call->master_lock held in W
static int media_player_play_init(struct media_player *mp) {
	media_player_shutdown(mp);

	// find call media suitable for playback
	struct call_media *media;
	for (GList *l = mp->ml->medias.head; l; l = l->next) {
		media = l->data;
		if (media->type_id != MT_AUDIO)
			continue;
		if (!MEDIA_ISSET(media, SEND))
			continue;
		if (media->streams.length == 0)
			continue;
		goto found;
	}
	media = NULL;
found:
	if (!media) {
		ilog(LOG_ERR, "No suitable SDP section for media playback");
		return -1;
	}
	mp->media = media;
	mp->sink = media->streams.head->data;
	mp->crypt_handler = determine_handler(&transport_protocols[PROTO_RTP_AVP], media, 1);

	return 0;
}


// call->master_lock held in W
static void media_player_play_start(struct media_player *mp) {
	// needed to have usable duration for some formats. ignore errors.
	avformat_find_stream_info(mp->fmtctx, NULL);

	mp->next_run = rtpe_now;
	// give ourselves a bit of a head start with decoding
	timeval_add_usec(&mp->next_run, -50000);
	media_player_read_packet(mp);
}
#endif


// call->master_lock held in W
int media_player_play_file(struct media_player *mp, const str *file) {
#ifdef WITH_TRANSCODING
	if (media_player_play_init(mp))
		return -1;

	char file_s[PATH_MAX];
	snprintf(file_s, sizeof(file_s), STR_FORMAT, STR_FMT(file));

	int ret = avformat_open_input(&mp->fmtctx, file_s, NULL, NULL);
	if (ret < 0) {
		ilog(LOG_ERR, "Failed to open media file for playback: %s", av_error(ret));
		return -1;
	}

	media_player_play_start(mp);

	return 0;
#else
	return -1;
#endif
}


#ifdef WITH_TRANSCODING
static int __mp_avio_read_wrap(void *opaque, uint8_t *buf, int buf_size) {
	struct media_player *mp = opaque;
	if (buf_size < 0)
		return AVERROR(EINVAL);
	if (buf_size == 0)
		return 0;
	if (!mp->read_pos.len)
		return AVERROR_EOF;

	int len = buf_size;
	if (len > mp->read_pos.len)
		len = mp->read_pos.len;
	memcpy(buf, mp->read_pos.s, len);
	str_shift(&mp->read_pos, len);
	return len;
}
static int __mp_avio_read(void *opaque, uint8_t *buf, int buf_size) {
	ilog(LOG_DEBUG, "__mp_avio_read(%i)", buf_size);
	int ret = __mp_avio_read_wrap(opaque, buf, buf_size);
	ilog(LOG_DEBUG, "__mp_avio_read(%i) = %i", buf_size, ret);
	return ret;
}
예제 #27
0
파일: ice.c 프로젝트: Zodiac-Evil/rtpengine
/* call must be locked R or W, agent must not be locked */
static void __do_ice_checks(struct ice_agent *ag) {
	GList *l;
	struct ice_candidate_pair *pair, *highest = NULL, *frozen = NULL, *valid;
	struct packet_stream *ps;
	GQueue retransmits = G_QUEUE_INIT;
	struct timeval next_run = {0,0};
	int have_more = 0;

	if (!ag) {
		ilog(LOG_ERR, "ice ag is NULL");
		return;
	}

	if (!ag->pwd[0].s)
		return;

	atomic64_set(&ag->last_activity, poller_now);

	__DBG("running checks, call "STR_FORMAT" tag "STR_FORMAT"", STR_FMT(&ag->call->callid),
			STR_FMT(&ag->media->monologue->tag));

	mutex_lock(&ag->lock);

	/* check if we're done and should start nominating pairs */
	if (AGENT_ISSET(ag, CONTROLLING) && !AGENT_ISSET(ag, NOMINATING) && ag->start_nominating.tv_sec) {
		if (timeval_cmp(&g_now, &ag->start_nominating) >= 0)
			__nominate_pairs(ag);
		timeval_lowest(&next_run, &ag->start_nominating);
	}

	/* triggered checks are preferred */
	pair = g_queue_pop_head(&ag->triggered);
	if (pair) {
		PAIR_CLEAR(pair, TRIGGERED);
		next_run = g_now;
		goto check;
	}

	/* find the highest-priority non-frozen non-in-progress pair */
	for (l = ag->all_pairs_list.head; l; l = l->next) {
		pair = l->data;

		/* skip dead streams */
		ps = pair->packet_stream;
		if (!ps || !ps->sfd)
			continue;
		if (PAIR_ISSET(pair, FAILED))
			continue;
		if (PAIR_ISSET(pair, SUCCEEDED) && !PAIR_ISSET(pair, TO_USE))
			continue;

		valid = __get_pair_by_component(ag->valid_pairs, pair->remote_candidate->component_id);

		if (PAIR_ISSET(pair, IN_PROGRESS)) {
			/* handle retransmits */
			/* but only if our priority is lower than any valid pair */
			if (valid && valid->pair_priority > pair->pair_priority)
				continue;

			if (timeval_cmp(&pair->retransmit, &g_now) <= 0)
				g_queue_push_tail(&retransmits, pair); /* can't run check directly
									  due to locks */
			else
				timeval_lowest(&next_run, &pair->retransmit);
			continue;
		}

		/* don't do anything else if we already have a valid pair */
		if (valid)
			continue;
		/* or if we're in or past the final phase */
		if (AGENT_ISSET2(ag, NOMINATING, COMPLETED))
			continue;

		have_more = 1;

		/* remember the first frozen pair in case we find nothing else */
		if (PAIR_ISSET(pair, FROZEN)) {
			if (!frozen)
				frozen = pair;
			continue;
		}

		if (!highest)
			highest = pair;
	}

	if (highest)
		pair = highest;
	else if (frozen)
		pair = frozen;
	else
		pair = NULL;

check:
	mutex_unlock(&ag->lock);

	if (pair)
		__do_ice_check(pair);

	while ((pair = g_queue_pop_head(&retransmits)))
		__do_ice_check(pair);


	/* determine when to run next */
	if (have_more)
		__agent_schedule(ag, 0);
	else if (next_run.tv_sec)
		__agent_schedule_abs(ag, &next_run); /* for retransmits */
}
예제 #28
0
/**
 * internal implementation
 */
int worker_rpc_impl(ei_cnode *ec, int s,int wpid)
{
	str module = STR_NULL;
	str function = STR_NULL;
	ei_x_buff args;
	ei_x_buff reply;
	struct msghdr msgh;
	struct iovec cnt[6];
	int rc;

	memset((void*)&args,0,sizeof(args));
	memset((void*)&reply,0,sizeof(reply));
	memset((void*)&msgh,0,sizeof(msgh));

	/* module name length */
	cnt[0].iov_base = &module.len;
	cnt[0].iov_len  = sizeof(int);

	/* function name length */
	cnt[1].iov_base = &function.len;
	cnt[1].iov_len  = sizeof(int);

	/* Erlang args size */
	cnt[2].iov_base = &args.buffsz;
	cnt[2].iov_len  = sizeof(int);

	/* get data size */
	msgh.msg_iov    = cnt;
	msgh.msg_iovlen = 3;
	while ((rc = recvmsg(s, &msgh, MSG_PEEK)) == -1 && errno == EAGAIN)
		;

	if (rc == -1){
		LM_ERR("recvmsg failed (socket=%d): %s\n",s,strerror(errno));
		goto err;
	}

	/* allocate space */
	module.s = (char*)pkg_malloc(module.len+1);
	if (!module.s) {
		LM_ERR("not enough memory\n");
		goto err;
	}

	function.s = (char*)pkg_malloc(function.len+1);
	if (!function.s) {
		LM_ERR("not enough memory\n");
		goto err;
	}

	args.buff = (char*)malloc(args.buffsz);
	if (!args.buff) {
		LM_ERR("malloc: not enough memory\n");
		goto err;
	}

	/* buffers */
	cnt[3].iov_base = module.s;
	cnt[3].iov_len  = module.len;

	cnt[4].iov_base = function.s;
	cnt[4].iov_len  = function.len;

	cnt[5].iov_base = args.buff;
	cnt[5].iov_len  = args.buffsz;

	/* get whole data */
	msgh.msg_iovlen = 6;
	while ((rc = recvmsg(s, &msgh, MSG_WAITALL)) == -1 && errno == EAGAIN)
		;

	if (rc == -1){
		LM_ERR("recvmsg failed (socket=%d): %s\n",s,strerror(errno));
		goto err;
	}

	/* fix str */
	module.s[module.len] = 0;
	function.s[function.len] = 0;

	LM_DBG("rpc: %.*s:%.*s(args)\n",STR_FMT(&module),STR_FMT(&function));

	EI_X_BUFF_PRINT(&args);

	if(!enode) {
		LM_NOTICE("there is no connected Erlang node\n");
		/* reply up with error */
		ei_x_format(&reply, "{error,cnode,~a}", "no_erlang_node");
		goto reply;
	}

	/* do RPC */
	if ((rc = ei_rpc(ec,enode->sockfd,module.s,function.s,args.buff,args.buffsz,&reply)) == ERL_ERROR)
	{
		reply.index = 0; /* re-use reply buffer */

		if (erl_errno)
		{
			ei_x_format(&reply, "{error,cnode,~s}", strerror(erl_errno));
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>: %s\n",enode->conn.nodename,enode->sockfd,strerror(erl_errno));
		}
		else if (errno)
		{
			ei_x_format(&reply, "{error,cnode,~s}", strerror(errno));
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>: %s\n",enode->conn.nodename,enode->sockfd,strerror(errno));
		}
		else
		{
			ei_x_format(&reply, "{error,cnode,~s}", "Unknown error.");
			LM_ERR("ei_rpc failed on node=<%s> socket=<%d>, Unknown error.\n",ec->thisalivename,enode->sockfd);
		}
	}

reply:
	EI_X_BUFF_PRINT(&reply);

	cnt[0].iov_base = (void*)&wpid;
	cnt[0].iov_len  = sizeof(int);

	/* send reply to Kamailio worker */
	cnt[1].iov_base = (void*)&reply.buffsz;
	cnt[1].iov_len  = sizeof(int);

	cnt[2].iov_base = (void*)reply.buff;
	cnt[2].iov_len  = reply.buffsz;

	msgh.msg_iovlen = 3;
	while ((rc = sendmsg(s, &msgh, 0)) == -1 && errno == EAGAIN)
		;

	if (rc == -1) {
		LM_ERR("sendmsg failed on socket=%d rpid_no=%d; %s\n",s, wpid, strerror(errno));
		goto err;
	};

	pkg_free(module.s);
	pkg_free(function.s);
	free(args.buff);
	ei_x_free(&reply);
	return 0;

err:
	pkg_free(module.s);
	pkg_free(function.s);
	free(args.buff);
	ei_x_free(&reply);
	abort(); /* cant't recover */
	return -1;
}
static bool
read_config(const char *file_path, Context *ctx)
{
    Variable *last_var = NULL;
    GList *itr;
    FILE *f;
    char line[LINE_SIZE];
    char name[NAME_SIZE];
    int tmp;

    // default values
    ctx->read_freq = READ_FREQ;
    ctx->days = DAYS;
    ctx->time_blocks = TIME_BLOCKS;
    ctx->read_counter = 0;
    ctx->enable_time_input = 1;
    ctx->enable_weekday_input = 1;
    ctx->inputs = NULL;
    ctx->outputs = NULL;
    ctx->expectations = NULL;
    ctx->expectation_blocks = NULL;
    ctx->time = NULL;
    ctx->weekday = NULL;

    f = fopen(file_path, "r");
    if (!f) {
        fprintf(stderr, "Failed to open %s\n", file_path);
        return false;
    }

    while (fgets(line, LINE_SIZE, f)) {
        float min = 0, max = 0;
        int ret;

        // empty or comment line
        if ((line[0] == '\n') || (line[0] == '#'))
            continue;

        ret = sscanf(line, "TIME_BLOCKS %d\n", &ctx->time_blocks);
        if (ret > 0) {
            last_var = NULL;
            continue;
        }

        ret = sscanf(line, "DAYS %d\n", &ctx->days);
        if (ret > 0) {
            last_var = NULL;
            continue;
        }

        ret = sscanf(line, "READ_FREQ %d\n", &ctx->read_freq);
        if (ret > 0) {
            last_var = NULL;
            continue;
        }

        ret = sscanf(line, "ENABLE_TIME_INPUT %d\n",
            &tmp);
        if (ret > 0) {
            ctx->enable_time_input = !!tmp;
            last_var = NULL;
            continue;
        }

        ret = sscanf(line, "ENABLE_WEEKDAY_INPUT %d\n",
            &tmp);
        if (ret > 0) {
            ctx->enable_weekday_input = !!tmp;
            last_var = NULL;
            continue;
        }

        ret = sscanf(line, "INPUT " STR_FMT(NAME_SIZE) " %f %f\n",
            name, &min, &max);
        if (ret > 0) {
            last_var = add_input(ctx, name, min, max);
            continue;
        }

        ret = sscanf(line, "OUTPUT " STR_FMT(NAME_SIZE) " %f %f\n",
            name, &min, &max);
        if (ret > 0) {
            last_var = add_output(ctx, name, min, max);
            add_expectation(ctx, last_var, name);
            continue;
        }

        ret = sscanf(line, "TERM " STR_FMT(NAME_SIZE) " %f %f\n",
            name, &min, &max);
        if (ret > 0) {
            if (!last_var) {
                fprintf(stderr, "Failed to find var for term %s\n", line);
                goto error;
            }
            add_term(ctx, last_var, name, min, max);
            continue;
        }

        fprintf(stderr, "Unknow configuration %s\n", line);
        goto error;
    }

    ctx->reads = 24 * 60 / ctx->read_freq * ctx->days;

    for (itr = ctx->inputs; itr; itr = itr->next) {
        Variable *var = itr->data;
        if (!var->terms)
            variable_add_terms(ctx, var);
    }

    for (itr = ctx->outputs; itr; itr = itr->next) {
        Variable *var = itr->data;
        if (!var->terms)
            variable_add_terms(ctx, var);
    }

    fclose(f);
    return true;

error:
    fclose(f);
    return false;
}
예제 #30
0
/*
 * Adds to request a new destination set that includes all highest
 * priority class contacts in contacts_avp.   Request URI is rewritten with
 * first contact and the remaining contacts (if any) are added as branches.
 * Removes used contacts from contacts_avp.  Returns 1, if contacts_avp
 * was not empty and a destination set was successfully added.  Returns -2,
 * if contacts_avp was empty and thus there was nothing to do.
 * Returns -1 in case of an error. */
int t_next_contacts(struct sip_msg* msg, char* key, char* value)
{
    struct usr_avp *avp, *prev;
    int_str val;
    str uri, dst, path;
    struct socket_info *sock;
    unsigned int flags;
    struct search_state st;

    /* Check if contacts_avp has been defined */
    if (contacts_avp.n == 0) {
		LM_ERR("feature has been disabled - "
			   "to enable define contacts_avp module parameter");
		return -1;
    }

    /* Load Request-URI and branches */

    /* Find first contacts_avp value */
    avp = search_first_avp(contacts_avp_type, contacts_avp, &val, &st);
    if (!avp) {
	LM_DBG("no AVPs - we are done!\n");
	return -2;
    }

    LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));

    if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
	== 0) {
	LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
	destroy_avp(avp);
	return -1;
    }
    
    /* Rewrite Request-URI */
    rewrite_uri(msg, &uri);
    if (dst.s && dst.len) set_dst_uri(msg, &dst);
    else reset_dst_uri(msg);
    if (path.s && path.len) set_path_vector(msg, &path);
    else reset_path_vector(msg);
    set_force_socket(msg, sock);
    setbflagsval(0, flags);

    if (avp->flags & Q_FLAG) {
	destroy_avp(avp);
	return 1;
    }
		
    /* Append branches until out of branches or Q_FLAG is set */
    prev = avp;
    while ((avp = search_next_avp(&st, &val))) {
	destroy_avp(prev);
	LM_DBG("next contact is <%.*s>\n", STR_FMT(&val.s));
	
	if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)
	    == 0) {
	    LM_ERR("decoding of branch info <%.*s> failed\n", STR_FMT(&val.s));
	    destroy_avp(avp);
	    return -1;
	}

	if (append_branch(msg, &uri, &dst, &path, 0, flags, sock) != 1) {
	    LM_ERR("appending branch failed\n");
	    destroy_avp(avp);
	    return -1;
	}

	if (avp->flags & Q_FLAG) {
	    destroy_avp(avp);
	    return 1;
	}
	prev = avp;
    }

    destroy_avp(prev);

    return 1;
}