Exemplo n.º 1
0
int update_sock_struct_from_via( union sockaddr_union* to,
								 struct sip_msg* msg,
								 struct via_body* via )
{
	struct hostent* he;
	str* name;
	int err;
	unsigned short port;

	port=0;
	if(via==msg->via1){
		/* _local_ reply, we ignore any rport or received value
		 * (but we will send back to the original port if rport is
		 *  present) */
		if ((msg->msg_flags&FL_FORCE_RPORT)||(via->rport))
			port=msg->rcv.src_port;
		else port=via->port;
		if(via->maddr)
			name= &(via->maddr->value);
		else
			name=&(via->host); /* received=ip in 1st via is ignored (it's
							  not added by us so it's bad) */
	}else{
		/* "normal" reply, we use rport's & received value if present */
		if (via->rport && via->rport->value.s){
			LM_DBG("using 'rport'\n");
			port=str2s(via->rport->value.s, via->rport->value.len, &err);
			if (err){
				LM_NOTICE("bad rport value(%.*s)\n",
					via->rport->value.len,via->rport->value.s);
				port=0;
			}
		}

		if (via->maddr){
			name= &(via->maddr->value);
			if (port==0) port=via->port?via->port:SIP_PORT;
		} else if (via->received){
			LM_DBG("using 'received'\n");
			name=&(via->received->value);
			/* making sure that we won't do SRV lookup on "received" */
			if (port==0) port=via->port?via->port:SIP_PORT;
		}else{
			LM_DBG("using via host\n");
			name=&(via->host);
			if (port==0) port=via->port;
		}
	}
	LM_DBG("trying SRV lookup\n");
	he=sip_resolvehost(name, &port, &via->proto, 0, 0);

	if (he==0){
		LM_NOTICE("resolve_host(%.*s) failure\n", name->len, name->s);
		return -1;
	}

	hostent2su( to, he, 0, port);
	return 1;
}
Exemplo n.º 2
0
static int trace_send_duplicate(char *buf, int len)
{
	union sockaddr_union* to;
	struct socket_info* send_sock;
	struct proxy_l * p;
	int proto;
	int ret;

	if(buf==NULL || len <= 0)
		return -1;

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;

	to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	if (to==0){
		LM_ERR("out of pkg memory\n");
		return -1;
	}

	/* create a temporary proxy*/
	proto = PROTO_UDP;
	p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
			proto, 0);
	if (p==0){
		LM_ERR("bad host name in uri\n");
		pkg_free(to);
		return -1;
	}

	hostent2su(to, &p->host, p->addr_idx,
				(p->port)?p->port:SIP_PORT);

	ret = -1;

	do {
		send_sock=get_send_socket(0, to, proto);
		if (send_sock==0){
			LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n",
					to->s.sa_family,proto);
			continue;
		}

		if (msg_send(send_sock, proto, to, 0, buf, len, NULL)<0){
			LM_ERR("cannot send duplicate message\n");
			continue;
		}
		ret = 0;
		break;
	}while( get_next_su( p, to, 0)==0 );

	free_proxy(p); /* frees only p content, not p itself */
	pkg_free(p);
	pkg_free(to);

	return ret;
}
Exemplo n.º 3
0
static union sockaddr_union *jsonrpc_get_dst(str *ip_port)
{
	static union sockaddr_union _su;
	struct hostent *hentity;
	char *p, bk;
	str host;
	str port;
	int iport;
	int err;

	if (!ip_port || !ip_port->len) {
		LM_ERR("no IP:port specified!\n");
		return NULL;
	}

	/* search for the port */
	p = memchr(ip_port->s, ':', ip_port->len);
	if (!p) {
		LM_ERR("invalid IP:port %.*s\n", ip_port->len, ip_port->s);
		return NULL;
	}
	host.s = ip_port->s;
	host.len = p - ip_port->s;

	/* remaining should be port */
	port.s = p + 1;
	port.len = ip_port->len - (host.len + 1/* : */);
	trim(&port);

	iport = str2s(port.s, port.len, &err);
	if (iport <= 0 || err != 0 || iport > 65535) {
		LM_ERR("Invalid port specified [%.*s]\n", port.len, port.s);
		return NULL;
	}

	trim(&host);

	/* null terminate host */
	bk = host.s[host.len];
	host.s[host.len] = 0;

	hentity = resolvehost(host.s, 0);
	host.s[host.len] = bk;
	if (!hentity) {
		LM_ERR("cannot resolve host %s\n", host.s);
		return NULL;
	}
	if(hostent2su(&_su, hentity, 0, iport)){
		LM_ERR("failed to resolve %s\n", host.s);
		return NULL;
	}
	
	return &_su;
}
Exemplo n.º 4
0
static int fixup_siptrace(void** param, int param_no) {
	char *duri = (char*) *param;
	struct sip_uri dup_uri;
	struct dest_info *dst = NULL;
	struct proxy_l * p = NULL;
	str dup_uri_str = { 0, 0 };

	if (param_no != 1) {
		LM_DBG("params:%s\n", (char*)*param);
		return 0;
	}
	if (!(*duri)) {
		LM_ERR("invalid dup URI\n");
		return -1;
	}
	LM_DBG("sip_trace URI:%s\n", (char*)*param);

	dup_uri_str.s = duri;
	dup_uri_str.len = strlen(dup_uri_str.s);
	memset(&dup_uri, 0, sizeof(struct sip_uri));

	if (parse_uri(dup_uri_str.s, dup_uri_str.len, &dup_uri) < 0) {
		LM_ERR("bad dup uri\n");
		return -1;
	}

	dst = (struct dest_info *) pkg_malloc(sizeof(struct dest_info));
	if (dst == 0) {
		LM_ERR("no more pkg memory left\n");
		return -1;
	}
	init_dest_info(dst);
	/* create a temporary proxy*/
	dst->proto = PROTO_UDP;
	p = mk_proxy(&dup_uri.host, (dup_uri.port_no) ? dup_uri.port_no : SIP_PORT,
			dst->proto);
	if (p == 0) {
		LM_ERR("bad host name in uri\n");
		pkg_free(dst);
		return -1;
	}
	hostent2su(&dst->to, &p->host, p->addr_idx, (p->port) ? p->port : SIP_PORT);

	pkg_free(*param);
	/* free temporary proxy*/
	if (p) {
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}

	*param = (void*) dst;
	return 0;
}
Exemplo n.º 5
0
int rl_add_repl_dst(modparam_t type, void *val)
{
	char *host;
	int hlen, port;
	int proto;
	struct hostent *he;
	str st;

	rl_dests = pkg_realloc(rl_dests, (rl_dests_nr + 1) * sizeof(rl_repl_dst_t));
	if (!rl_dests) {
		LM_ERR("oom\n");
		return -1;
	}

	if (parse_phostport(val, strlen(val), &host, &hlen, &port, &proto) < 0) {
		LM_ERR("Bad replication destination IP!\n");
		return -1;
	}

	if (proto == PROTO_NONE)
		proto = PROTO_UDP;

	st.s = host;
	st.len = hlen;
	he = sip_resolvehost(&st, (unsigned short *)&port,
							  (unsigned short *)&proto, 0, 0);
	if (!he) {
		LM_ERR("Cannot resolve host: %.*s\n", hlen, host);
		return -1;
	}
	if (!port) {
		LM_ERR("no port specified for host %.*s\n", hlen, host);
		return -1;
	}

	rl_dests[rl_dests_nr].id = rl_dests_nr;
	rl_dests[rl_dests_nr].dst.s = (char *)val;
	rl_dests[rl_dests_nr].dst.len = strlen(rl_dests[rl_dests_nr].dst.s);
	hostent2su(&rl_dests[rl_dests_nr].to, he, 0, port);

	LM_DBG("Added destination <%.*s>\n",
			rl_dests[rl_dests_nr].dst.len, rl_dests[rl_dests_nr].dst.s);

	/* init done */
	rl_dests_nr++;

	return 1;
}
Exemplo n.º 6
0
int
natping_contact(str contact, struct dest_info *dst) {
	struct sip_uri curi;
	struct hostent *he;
	str p_method, p_from;

	if (natping_method != NULL) {
		/* XXX: add send_sock handling */
		p_method.s = natping_method;
		p_method.len = strlen(p_method.s);
		p_from.s = "sip:registrar"; /* XXX */
		p_from.len = strlen(p_from.s);
		if (tmb.t_request(&p_method, &contact, &contact, &p_from,
		    NULL, NULL, NULL, NULL, NULL) == -1) {
			LOG(L_ERR, "ERROR: nathelper::natping(): t_request() failed\n");
			return -1;
		}
	} else {
		if (parse_uri(contact.s, contact.len, &curi) < 0) {
			LOG(L_ERR, "ERROR: nathelper::natping: can't parse contact uri\n");
			return -1;
		}
		if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE)
			return -1;
		if (curi.port_no == 0)
			curi.port_no = SIP_PORT;
		he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP);
		if (he == NULL){
			LOG(L_ERR, "ERROR: nathelper::natping: can't resolve host\n");
			return -1;
		}
		hostent2su(&dst->to, he, 0, curi.port_no);
		if (dst->send_sock == NULL) {
			dst->send_sock = force_socket ? force_socket :
			    get_send_socket(0, &dst->to, PROTO_UDP);
		}
		if (dst->send_sock == NULL) {
			LOG(L_ERR, "ERROR: nathelper::natping: can't get sending socket\n");
			return -1;
		}
		dst->proto=PROTO_UDP;
		udp_send(dst, (char *)sbuf, sizeof(sbuf));
	}
	return 1;
}
Exemplo n.º 7
0
static int add_replication_dest(modparam_t type, void *val)
{
	struct replication_dest *rd;
	char *host;
	int hlen, port;
	int proto;
	struct hostent *he;
	str st;

	rd = pkg_malloc(sizeof(*rd));
	memset(rd, 0, sizeof(*rd));

	if (parse_phostport(val, strlen(val), &host, &hlen, &port, &proto) < 0) {
		LM_ERR("Bad replication destination IP!\n");
		return -1;
	}

	if (proto == PROTO_NONE)
		proto = PROTO_UDP;

	if (proto != PROTO_UDP) {
		LM_ERR("Dialog replication only supports UDP packets!\n");
		return -1;
	}

	st.s = host;
	st.len = hlen;
	he = sip_resolvehost(&st, (unsigned short *)&port,
							  (unsigned short *)&proto, 0, 0);
	if (!he) {
		LM_ERR("Cannot resolve host: %.*s\n", hlen, host);
		return -1;
	}

	hostent2su(&rd->to, he, 0, port);

	rd->next = replication_dests;
	replication_dests = rd;

	return 1;
}
Exemplo n.º 8
0
/* resolve host, port, proto using sip rules (e.g. use SRV if port=0 a.s.o)
 *  and write the result in the sockaddr_union to
 *  returns -1 on error (resolve failed), 0 on success */
int sip_hostport2su(union sockaddr_union* su, str* name, unsigned short port,
						char* proto)
{
	struct hostent* he;
	
	he=sip_resolvehost(name, &port, proto);
	if (he==0){
		ser_error=E_BAD_ADDRESS;
		LOG(L_ERR, "ERROR: sip_hostport2su: could not resolve hostname:"
					" \"%.*s\"\n", name->len, name->s);
		goto error;
	}
	/* port filled by sip_resolvehost if empty*/
	if (hostent2su(su, he, 0, port)<0){
		ser_error=E_BAD_ADDRESS;
		goto error;
	}
	return 0;
error:
	return -1;
}
Exemplo n.º 9
0
/* add a new information in the backend list*/
int add_info(table_entry_t **data, int *int_vals, unsigned long last_attempt, char **str_vals)
{
	char *host;
	int hlen, port;
	struct hostent *he;
	struct module_list *module;
	struct module_timestamp *new_timestamp;
	uint64_t ctime;
	int proto;
	int cluster_id;
	table_entry_t *head = NULL;
	table_entry_info_t *info_head = NULL;
	table_entry_value_t *value = NULL;
	str st;
	char *url;
	char *description;

	if (int_vals[INT_VALS_MACHINE_ID_COL] == server_id) {
		return 0;
	}

	url = str_vals[STR_VALS_URL_COL];

	if (url == NULL) {
		LM_ERR("no path specified\n");
		goto error;
	}

	if (parse_phostport(url, strlen(url), &host, &hlen, &port, &proto) < 0) {
		LM_ERR("Bad replication destination IP!\n");
		goto error;
	}

	if (proto == PROTO_NONE)
		proto = PROTO_UDP;

	cluster_id = int_vals[INT_VALS_CLUSTER_ID_COL];

	for (head = *data; head; head = head->next) {
		if (head->cluster_id == cluster_id) {
			info_head = head->info;
			while (info_head && info_head->proto != proto)
				info_head = info_head->next;

			if (!info_head) {
				info_head = shm_malloc(sizeof *info_head);
				if (!info_head) {
					LM_ERR("no more shm memory\n");
					goto error;
				}
				info_head->proto = proto;
				info_head->next = head->info;
				info_head->value = NULL;
				head->info = info_head;
			}
			break;
		}
	}

	if (!head) {
		head = shm_malloc(sizeof *head);
		if (!head) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		head->cluster_id = cluster_id;
		head->info = shm_malloc(sizeof(table_entry_info_t));
		if (!head->info) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		head->info->proto = proto;
		head->info->next = NULL;
		head->info->value = NULL;
		info_head = head->info;
		info_head->proto = proto;
		head->next = *data;
		*data = head;
	}

	/* allocating memory*/
	value = shm_malloc(sizeof *value);
	if (!value) {
		LM_ERR("no more shm memory\n");
		goto error;
	}

	value->machine_id = int_vals[INT_VALS_MACHINE_ID_COL];
	value->id = int_vals[INT_VALS_CLUSTERER_ID_COL];
	value->state = int_vals[INT_VALS_STATE_COL];
	value->last_attempt = last_attempt;
	value->duration = int_vals[INT_VALS_DURATION_COL];
	value->failed_attempts = int_vals[INT_VALS_FAILED_ATTEMPTS_COL];
	value->no_tries = int_vals[INT_VALS_NO_TRIES_COL];
	value->dirty_bit = 0;
	value->prev_no_tries = -1;
	value->in_timestamps = NULL;
	description = str_vals[STR_VALS_DESCRIPTION_COL];

	value->path.s = shm_malloc(strlen(url) * sizeof(char));

	if (!value->path.s) {
		LM_ERR("insufficient shm memory\n");
		goto error;
	}

	st.s = host;
	st.len = hlen;

	he = sip_resolvehost(&st, (unsigned short *) &port,
		(unsigned short *) &proto, 0, 0);
	if (!he) {
		LM_ERR("Cannot resolve host: %.*s\n", hlen, host);
		goto error;
	}

	hostent2su(&value->addr, he, 0, port);

	value->path.len = strlen(url);
	memcpy(value->path.s, url, value->path.len);

	if (strlen(description) != 0) {
		value->description.len = strlen(description);
		value->description.s = shm_malloc(value->description.len * sizeof(char));
		if (value->description.s == NULL) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		memcpy(value->description.s, description, value->description.len);
	} else {
		value->description.s = NULL;
		value->description.len = 0;
	}

	ctime = time(0);
	for (module = clusterer_modules; module; module = module->next) {
		if (cluster_id == module->accept_cluster_id && proto == module->proto) {
			new_timestamp = create_module_timestamp(ctime, module);
			if (new_timestamp == NULL)
				break;
			new_timestamp->next = value->in_timestamps;
			value->in_timestamps = new_timestamp;
		}
	}

	value->next = info_head->value;
	info_head->value = value;
	/* everything ok */
	return 0;
error:
	if (value) {
		if (value->description.s)
			shm_free(value->description.s);

		if (value->path.s)
			shm_free(value->path.s);
		shm_free(value);
	}
	if (info_head) {
		if (info_head->value == NULL) {
			if (head != NULL)
				head->info = head->info->next;
			shm_free(info_head);
		}
	}
	if (head) {
		if (head->info == NULL) {
			*tdata = (*tdata)->next;
			shm_free(head);
		}
	}
	return -1;
}
Exemplo n.º 10
0
/* introduce a new uac to transaction; returns its branch id (>=0)
   or error (<0); it doesn't send a message yet -- a reply to it
   might interfere with the processes of adding multiple branches
*/
static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
							str* next_hop, str* path, struct proxy_l *proxy)
{
	unsigned short branch;
	int do_free_proxy;
	int ret;

	branch=t->nr_of_outgoings;
	if (branch==MAX_BRANCHES) {
		LM_ERR("maximum number of branches exceeded\n");
		ret=E_CFG;
		goto error;
	}

	/* check existing buffer -- rewriting should never occur */
	if (t->uac[branch].request.buffer.s) {
		LM_CRIT("buffer rewrite attempt\n");
		ret=ser_error=E_BUG;
		goto error;
	}

	/* set proper RURI to request to reflect the branch */
	request->new_uri=*uri;
	request->parsed_uri_ok=0;
	request->dst_uri=*next_hop;
	request->path_vec=*path;

	if ( pre_print_uac_request( t, branch, request)!= 0 ) {
		ret = -1;
		goto error01;
	}

	/* check DNS resolution */
	if (proxy){
		do_free_proxy = 0;
	}else {
		proxy=uri2proxy( request->dst_uri.len ?
			&request->dst_uri:&request->new_uri, PROTO_NONE );
		if (proxy==0)  {
			ret=E_BAD_ADDRESS;
			goto error01;
		}
		do_free_proxy = 1;
	}

	msg_callback_process(request, REQ_PRE_FORWARD, (void *)proxy);

	if ( !(t->flags&T_NO_DNS_FAILOVER_FLAG) ) {
		t->uac[branch].proxy = shm_clone_proxy( proxy , do_free_proxy );
		if (t->uac[branch].proxy==NULL) {
			ret = E_OUT_OF_MEM;
			goto error02;
		}
	}

	/* use the first address */
	hostent2su( &t->uac[branch].request.dst.to,
		&proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT);
	t->uac[branch].request.dst.proto = proxy->proto;

	if ( update_uac_dst( request, &t->uac[branch] )!=0) {
		ret = ser_error;
		goto error02;
	}

	/* things went well, move ahead */
	t->uac[branch].uri.s=t->uac[branch].request.buffer.s+
		request->first_line.u.request.method.len+1;
	t->uac[branch].uri.len=request->new_uri.len;
	t->uac[branch].br_flags = getb0flags();
	t->uac[branch].added_rr = count_local_rr( request );
	t->nr_of_outgoings++;

	/* done! */
	ret=branch;

error02:
	if(do_free_proxy) {
		free_proxy( proxy );
		pkg_free( proxy );
	}
error01:
	post_print_uac_request( request, uri, next_hop);
error:
	return ret;
}
Exemplo n.º 11
0
static int trace_send_hep_duplicate(str *body, str *fromproto, str *fromip,
		unsigned short fromport, str *toproto, str *toip, unsigned short toport)
{
	struct proxy_l * p=NULL /* make gcc happy */;
	int ret;
	union sockaddr_union from_su;
	union sockaddr_union to_su;
	unsigned int proto;
	struct socket_info* send_sock;
	union sockaddr_union* to = NULL;

	int heplen;
	char *hepbuf;

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

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;

	/* Convert proto:ip:port to sockaddress union SRC IP */
	if (pipport2su(fromproto, fromip, fromport, &from_su, &proto)==-1 ||
	(pipport2su(toproto, toip, toport, &to_su, &proto)==-1))
		goto error;

	/* check if from and to are in the same family*/
	if(from_su.s.sa_family != to_su.s.sa_family) {
		LM_ERR("ERROR: trace_send_hep_duplicate: interworking detected ?\n");
		goto error;
	}


	/* create a temporary proxy*/
	proto = PROTO_UDP;
	p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,proto, 0);
	if (p==0){
		LM_ERR("bad host name in uri\n");
		return -1;
	}

	to=(union sockaddr_union*)pkg_malloc(sizeof(union sockaddr_union));
	if (to==0){
		LM_ERR("out of pkg memory\n");
		return -1;
	}

	hostent2su(to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);

	if (hep_api.pack_hep(&from_su, to, proto, body->s, body->len,
				&hepbuf, &heplen)) {
		LM_ERR("failed to do hep packing\n");
		return -1;
	}

	ret = -1;

	do {
		send_sock=get_send_socket(0, to, proto);
		if (send_sock==0){
			LM_ERR("can't forward to af %d, proto %d no corresponding listening socket\n",
					to->s.sa_family,proto);
			continue;
		}

		if (msg_send(send_sock, PROTO_HEP, to, 0, hepbuf, heplen, NULL)<0){
			LM_ERR("cannot send duplicate message\n");
			continue;
		}
		ret = 0;
		break;
	}while( get_next_su( p, to, 0)==0 );
	free_proxy(p); /* frees only p content, not p itself */
	pkg_free(p);
	pkg_free(to);
	pkg_free(hepbuf);

	return ret;
error:
	if(p)
	{
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	if(to) pkg_free(to);
	return -1;
}
Exemplo n.º 12
0
static int mi_mod_init(void)
{
	unsigned int port_no;
	int n;
	struct stat filestat;
	struct hostent * host;
	char *p, *host_s;
	str port_str;

	/* checking the mi_socket module param */
	LM_DBG("testing socket existance...\n");

	if( mi_socket==NULL || *mi_socket == 0) {
		LM_ERR("no DATAGRAM_ socket configured\n");
		return -1;
	}

	LM_DBG("the socket's name/address is %s\n", mi_socket);

	memset( &mi_dtgram_addr, 0, sizeof(mi_dtgram_addr) );

	if(strncmp(mi_socket, "udp:",4) == 0)
	{
		/*for an UDP socket*/
		LM_DBG("we have an udp socket\n");
		/*separate proto and host */
		p = mi_socket+4;
		if( (*(p)) == '\0') {
			LM_ERR("malformed ip address\n");
			return -1;
		}
		host_s=p;
		LM_DBG("the remaining address after separating the protocol is %s\n",p);

		if( (p = strrchr(p+1, ':')) == 0 ) {
			LM_ERR("no port specified\n");
			return -1;
		}

		/*the address contains a port number*/
		*p = '\0';
		p++;
		port_str.s = p;
		port_str.len = strlen(p);
		LM_DBG("the port string is %s\n", p);
		if(str2int(&port_str, &port_no) != 0 ) {
			LM_ERR("there is not a valid number port\n");
			return -1;
		}
		*p = '\0';
		if (port_no<1024  || port_no>MAX_NB_PORT)
		{
			LM_ERR("invalid port number; must be in [1024,%d]\n",MAX_NB_PORT);
			return -1;
		}
		
		if(! (host = resolvehost(host_s)) ) {
			LM_ERR("failed to resolve %s\n", host_s);
			return -1;
		}
		LM_DBG("the ip is %s\n",host_s);
		if(hostent2su( &(mi_dtgram_addr.udp_addr), host, 0, port_no ) !=0){
			LM_ERR("failed to resolve %s\n", mi_socket);
			return -1;
		}
		mi_socket_domain = host->h_addrtype;
		goto done;
	} 
	/* in case of a Unix socket*/
	LM_DBG("we have an UNIX socket\n");
		
	n=stat(mi_socket, &filestat);
	if( n==0) {
		LM_INFO("the socket %s already exists, trying to delete it...\n", mi_socket);
		if(config_check==0) {
			if (unlink(mi_socket)<0) {
				LM_ERR("cannot delete old socket: %s\n", strerror(errno));
				return -1;
			}
		}
	} else if (n<0 && errno!=ENOENT) {
		LM_ERR("socket stat failed:%s\n", strerror(errno));
		return -1;
	}

	/* check mi_unix_socket_mode */
	if(!mi_unix_socket_mode) {
		LM_WARN("cannot specify mi_unix_socket_mode = 0, forcing it to rw-------\n");
		mi_unix_socket_mode = S_IRUSR| S_IWUSR;
	}
	
	if (mi_unix_socket_uid_s) {
		if (user2uid(&mi_unix_socket_uid, &mi_unix_socket_gid, mi_unix_socket_uid_s)<0) {
			LM_ERR("bad user name %s\n", mi_unix_socket_uid_s);
			return -1;
		}
	}
	
	if (mi_unix_socket_gid_s) {
		if (group2gid(&mi_unix_socket_gid, mi_unix_socket_gid_s)<0) {
			LM_ERR("bad group name %s\n", mi_unix_socket_gid_s);
			return -1;
		}
	}

	/*create the unix socket address*/
	mi_dtgram_addr.unix_addr.sun_family = AF_LOCAL;
	memcpy( mi_dtgram_addr.unix_addr.sun_path, mi_socket, strlen(mi_socket));

done:
	/* add space for extra processes */
	register_procs(mi_procs[0].no);
	/* add child to update local config framework structures */
	cfg_register_child(mi_procs[0].no);

	return 0;
}
static evi_reply_sock* datagram_parse(str socket, int is_unix)
{
	evi_reply_sock *sock = NULL;
	unsigned short port = 0;
	char *p = NULL, *host = 0;
	int len = 0;
	struct hostent *hentity;

	if (!socket.len || !socket.s) {
		LM_ERR("no socket specified\n");
		return NULL;
	}

	len = socket.len;
	host = socket.s;
	if (!is_unix) {
		p = memchr(host, COLON_C, len);
		if (!p || p == host) {
			LM_ERR("port not specified <%.*s>\n", len, host);
			return NULL;
		}
		port = str2s(p + 1, host + len - p - 1, 0);
		if (port == 0) {
			LM_DBG("malformed port: %.*s\n",
					(int)(host + len - p - 1), p + 1);
			return NULL;
		}
		LM_DBG("port is %d\n", port);
		len = p - host;
	}

	/* host */
	if (!host || len <= 0) {
		LM_ERR("malformed address %s\n", host);
		goto error;
	}
	sock = shm_malloc(sizeof(evi_reply_sock) + len);
	if (!sock) {
		LM_ERR("no more memory for socket\n");
		return NULL;
	}

	memset(sock, 0, sizeof(evi_reply_sock));

	/* only UDP has port */
	if (port) {
		sock->flags = EVI_PORT;
		sock->port = port;
		
		/* also build sockaddr */
		*p = 0;
		hentity = resolvehost(host, 0);
		if (!hentity) {
			LM_ERR("cannot resolve host %s\n", host);
			goto error;
		}
		if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){
			LM_ERR("failed to resolve %s\n", host);
			goto error;
		}
		sock->flags |= EVI_SOCKET | DGRAM_UDP_FLAG;
	} else {
		sock->src_addr.unix_addr.sun_family = AF_LOCAL;
		memcpy(sock->src_addr.unix_addr.sun_path, host, len);
		sock->src_addr.unix_addr.sun_path[len] = 0;
		sock->flags |= EVI_SOCKET | DGRAM_UNIX_FLAG;
	}

	LM_DBG("address is <%.*s>\n", len, host);
	sock->address.s = (char *) (sock + 1);
	sock->address.len = len;
	memcpy(sock->address.s, host, len);
	sock->flags |= EVI_ADDRESS;

	/* needs expire */
	sock->flags |= EVI_EXPIRE;

	return sock;
error:
	if (sock)
		shm_free(sock);
	return NULL;
}
Exemplo n.º 14
0
/* ret= 0! if action -> end of list(e.g DROP), 
      > 0 to continue processing next actions
   and <0 on error */
int do_action(struct action* a, struct sip_msg* msg)
{
	int ret;
	int v;
	int sec,usec;
	union sockaddr_union* to;
	struct proxy_l* p;
	char* tmp;
	char *new_uri, *end, *crt;
	int len,i;
	int user = 0;
	int expires = 0;
	str vals[5];
	str result;
	struct sip_uri uri, next_hop;
	struct sip_uri *u;
	unsigned short port;
	int cmatch;
	struct action *aitem;
	struct action *adefault;
	pv_spec_t *spec;
	pv_elem_p model;
	pv_value_t val;
	pv_elem_t *pve;
	str name_s;
	struct timeval start;
	int end_time;
	action_elem_t *route_params_bak;
	int route_params_number_bak;

	/* reset the value of error to E_UNSPEC so avoid unknowledgable
	   functions to return with error (status<0) and not setting it
	   leaving there previous error; cache the previous value though
	   for functions which want to process it */
	prev_ser_error=ser_error;
	ser_error=E_UNSPEC;

	start_expire_timer(start,execmsgthreshold);

	ret=E_BUG;
	switch ((unsigned char)a->type){
		case DROP_T:
				script_trace("core", "drop", msg, a->line) ;
				action_flags |= ACT_FL_DROP;
		case EXIT_T:
				script_trace("core", "exit", msg, a->line) ;
				ret=0;
				action_flags |= ACT_FL_EXIT;
			break;
		case RETURN_T:
				script_trace("core", "return", msg, a->line) ;
				if (a->elem[0].type == SCRIPTVAR_ST)
				{
					spec = (pv_spec_t*)a->elem[0].u.data;
					if(pv_get_spec_value(msg, spec, &val)!=0
						|| (val.flags&PV_VAL_NULL))
					{
						ret=-1;
					} else {
						if(!(val.flags&PV_VAL_INT))
							ret = 1;
						else
							ret = val.ri;
					}
					pv_value_destroy(&val);
				} else {
					ret=a->elem[0].u.number;
				}
				action_flags |= ACT_FL_RETURN;
			break;
		case FORWARD_T:
			script_trace("core", "forward", msg, a->line) ;
			if (a->elem[0].type==NOSUBTYPE){
				/* parse uri and build a proxy */
				if (msg->dst_uri.len) {
					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len,
						&next_hop);
					u = &next_hop;
				} else {
					ret = parse_sip_msg_uri(msg);
					u = &msg->parsed_uri;
				}
				if (ret<0) {
					LM_ERR("forward: bad_uri dropping packet\n");
					break;
				}
				/* create a temporary proxy*/
				p=mk_proxy(u->maddr_val.len?&u->maddr_val:&u->host,
					u->port_no, u->proto, (u->type==SIPS_URI_T)?1:0 );
				if (p==0){
					LM_ERR("bad host name in uri, dropping packet\n");
					ret=E_BAD_ADDRESS;
					goto error_fwd_uri;
				}
				ret=forward_request(msg, p);
				free_proxy(p); /* frees only p content, not p itself */
				pkg_free(p);
				if (ret==0) ret=1;
			}else if ((a->elem[0].type==PROXY_ST)) {
				ret=forward_request(msg,(struct proxy_l*)a->elem[0].u.data);
				if (ret==0) ret=1;
			}else{
				LM_ALERT("BUG in forward() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
			}
			break;
		case SEND_T:
			script_trace("core", "send", msg, a->line) ;
			if (a->elem[0].type!= PROXY_ST){
				LM_ALERT("BUG in send() type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if (a->elem[1].u.data) {
				if (a->elem[1].type != SCRIPTVAR_ELEM_ST){
					LM_ALERT("BUG in send() header type %d\n",a->elem[1].type);
					ret=E_BUG;
					break;
				} else {
					pve = (pv_elem_t *)a->elem[1].u.data;
				}
			} else {
				pve = NULL;
			}
			to=(union sockaddr_union*)
					pkg_malloc(sizeof(union sockaddr_union));
			if (to==0){
				LM_ERR("memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			
			p=(struct proxy_l*)a->elem[0].u.data;
			
			ret=hostent2su(to, &p->host, p->addr_idx,
						(p->port)?p->port:SIP_PORT );
			if (ret==0){
				if (pve) {
					if ( pv_printf_s(msg, pve, &name_s)!=0 || 
							name_s.len == 0 || name_s.s == NULL) {
						LM_WARN("cannot get string for value\n");
						ret=E_UNSPEC;
						break;
					}
					/* build new msg */
					tmp = pkg_malloc(msg->len + name_s.len);
					if (!tmp) {
						LM_ERR("memory allocation failure\n");
						ret = E_OUT_OF_MEM;
						break;
					}
					LM_DBG("searching for first line %d\n",
							msg->first_line.len);
					/* search first line of previous msg */
					/* copy headers */
					len = msg->first_line.len;
					memcpy(tmp, msg->buf, len);
					memcpy(tmp + len, name_s.s, name_s.len);
					memcpy(tmp + len + name_s.len,
							msg->buf + len, msg->len - len);
					ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/,
							tmp, msg->len + name_s.len);
					pkg_free(tmp);
				} else {
					ret = msg_send(0/*send_sock*/, p->proto, to, 0/*id*/,
							msg->buf, msg->len);
				}
				if (ret!=0 && p->host.h_addr_list[p->addr_idx+1])
					p->addr_idx++;
			}
			pkg_free(to);
			if (ret==0)
				ret=1;
			break;
		case LOG_T:
			script_trace("core", "log", msg, a->line) ;
			if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){
				LM_ALERT("BUG in log() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
				break;
			}
			LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string);
			ret=1;
			break;
		case APPEND_BRANCH_T:
			script_trace("core", "append_branch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in append_branch %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[0].u.s.s==NULL) {
				ret = append_branch(msg, 0, &msg->dst_uri, &msg->path_vec,
					get_ruri_q(), getb0flags(), msg->force_send_socket);
				/* reset all branch info */
				msg->force_send_socket = 0;
				setb0flags(0);
				set_ruri_q(Q_UNSPECIFIED);
				if(msg->dst_uri.s!=0)
					pkg_free(msg->dst_uri.s);
				msg->dst_uri.s = 0;
				msg->dst_uri.len = 0;
				if(msg->path_vec.s!=0)
					pkg_free(msg->path_vec.s);
				msg->path_vec.s = 0;
				msg->path_vec.len = 0;
			} else {
				ret = append_branch(msg, &a->elem[0].u.s, &msg->dst_uri, 
					&msg->path_vec, a->elem[1].u.number, getb0flags(),
					msg->force_send_socket);
			}
			break;
		case REMOVE_BRANCH_T:
			script_trace("core", "remove_branch", msg, a->line) ;
			if (a->elem[0].type == SCRIPTVAR_ST) {
				spec = (pv_spec_t*)a->elem[0].u.data;
				if( pv_get_spec_value(msg, spec, &val)!=0
				|| (val.flags&PV_VAL_NULL) || !(val.flags&PV_VAL_INT) ) {
					ret=-1;
					break;
				}
				i = val.ri;
			} else {
				i=a->elem[0].u.number;
			}
			ret = (remove_branch((unsigned int)i)==0)?1:-1;
			break;
		case LEN_GT_T:
			script_trace("core", "len_gt", msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST) {
				LM_ALERT("BUG in len_gt type %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1;
			break;
		case SET_DEBUG_T:
			script_trace("core", "set_debug", msg, a->line) ;
			if (a->elem[0].type==NUMBER_ST)
				set_proc_debug_level(a->elem[0].u.number);
			else
				reset_proc_debug_level();
			ret = 1;
			break;
		case SETFLAG_T:
			script_trace("core", "setflag", msg, a->line) ;
			ret = setflag( msg, a->elem[0].u.number );
			break;
		case RESETFLAG_T:
			script_trace("core", "resetflag", msg, a->line) ;
			ret = resetflag( msg, a->elem[0].u.number );
			break;
		case ISFLAGSET_T:
			script_trace("core", "isflagset", msg, a->line) ;
			ret = isflagset( msg, a->elem[0].u.number );
			break;
		case SETSFLAG_T:
			script_trace("core", "setsflag", msg, a->line) ;
			ret = setsflag( a->elem[0].u.number );
			break;
		case RESETSFLAG_T:
			script_trace("core", "resetsflag", msg, a->line) ;
			ret = resetsflag( a->elem[0].u.number );
			break;
		case ISSFLAGSET_T:
			script_trace("core", "issflagset", msg, a->line) ;
			ret = issflagset( a->elem[0].u.number );
			break;
		case SETBFLAG_T:
			script_trace("core", "setbflag", msg, a->line) ;
			ret = setbflag( a->elem[0].u.number, a->elem[1].u.number );
			break;
		case RESETBFLAG_T:
			script_trace("core", "resetbflag", msg, a->line) ;
			ret = resetbflag( a->elem[0].u.number, a->elem[1].u.number  );
			break;
		case ISBFLAGSET_T:
			script_trace("core", "isbflagset", msg, a->line) ;
			ret = isbflagset( a->elem[0].u.number, a->elem[1].u.number  );
			break;
		case ERROR_T:
			script_trace("core", "error", msg, a->line) ;
			if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){
				LM_ALERT("BUG in error() types %d, %d\n",
						a->elem[0].type, a->elem[1].type);
				ret=E_BUG;
				break;
			}
			LM_ERR("error(\"%s\", \"%s\") not implemented yet\n",
				a->elem[0].u.string, a->elem[1].u.string);
			ret=1;
			break;
		case ROUTE_T:
			script_trace("route", rlist[a->elem[0].u.number].name, msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST){
				LM_ALERT("BUG in route() type %d\n",
						a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if ((a->elem[0].u.number>RT_NO)||(a->elem[0].u.number<0)){
				LM_ALERT("BUG - invalid routing table number in"
							"route(%lu)\n", a->elem[0].u.number);
				ret=E_CFG;
				break;
			}
			/* check if the route has parameters */
			if (a->elem[1].type != 0) {
				if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ELEM_ST) {
					LM_ALERT("BUG in route() type %d/%d\n",
							a->elem[1].type, a->elem[2].type);
					ret=E_BUG;
					break;
				}
				route_params_bak = route_params;
				route_params = (action_elem_t *)a->elem[2].u.data;
				route_params_number_bak = route_params_number;
				route_params_number = a->elem[1].u.number;

				return_code=run_actions(rlist[a->elem[0].u.number].a, msg);
				route_params = route_params_bak;
				route_params_number = route_params_number_bak;
			} else {
				return_code=run_actions(rlist[a->elem[0].u.number].a, msg);
			}
			ret=return_code;
			break;
		case REVERT_URI_T:
			script_trace("core", "revert_uri", msg, a->line) ;
			if (msg->new_uri.s) {
				pkg_free(msg->new_uri.s);
				msg->new_uri.len=0;
				msg->new_uri.s=0;
				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
			};
			ret=1;
			break;
		case SET_HOST_T:
		case SET_HOSTPORT_T:
		case SET_USER_T:
		case SET_USERPASS_T:
		case SET_PORT_T:
		case SET_URI_T:
		case PREFIX_T:
		case STRIP_T:
		case STRIP_TAIL_T:
				script_trace("core", 
					(unsigned char)a->type == SET_HOST_T     ? "set_host" :
					(unsigned char)a->type == SET_HOSTPORT_T ? "set_hostport" : 
					(unsigned char)a->type == SET_USER_T     ? "set_user" :
					(unsigned char)a->type == SET_USERPASS_T ? "set_userpass" : 
					(unsigned char)a->type == SET_PORT_T     ? "set_port" :
					(unsigned char)a->type == SET_URI_T      ? "set_uri" : 
					(unsigned char)a->type == PREFIX_T       ? "prefix" :
					(unsigned char)a->type == STRIP_T  ? "strip" : "strip_tail",
					msg, a->line);
				user=0;
				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
					if (a->elem[0].type!=NUMBER_ST) {
						LM_ALERT("BUG in set*() type %d\n",
							a->elem[0].type);
						break;
					}
				} else if (a->elem[0].type!=STR_ST){
					LM_ALERT("BUG in set*() type %d\n",
							a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (a->type==SET_URI_T) {
					if (set_ruri( msg, &a->elem[0].u.s) ) {
						LM_ERR("failed to set new RURI\n");
						ret=E_OUT_OF_MEM;
						break;
					}
					ret=1;
					break;
				}
				if (msg->new_uri.s) {
					tmp=msg->new_uri.s;
					len=msg->new_uri.len;
				}else{
					tmp=msg->first_line.u.request.uri.s;
					len=msg->first_line.u.request.uri.len;
				}
				if (parse_uri(tmp, len, &uri)<0){
					LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp);
					ret=E_UNSPEC;
					break;
				}
				
				new_uri=pkg_malloc(MAX_URI_SIZE);
				if (new_uri==0){
					LM_ERR("memory allocation failure\n");
					ret=E_OUT_OF_MEM;
					break;
				}
				end=new_uri+MAX_URI_SIZE;
				crt=new_uri;
				/* begin copying */
				len = (uri.user.len?uri.user.s:uri.host.s) - tmp;
				if (crt+len>end) goto error_uri;
				memcpy(crt,tmp,len);crt+=len;

				if (a->type==PREFIX_T) {
					if (crt+a->elem[0].u.s.len>end) goto error_uri;
					memcpy( crt, a->elem[0].u.s.s, a->elem[0].u.s.len);
					crt+=a->elem[0].u.s.len;
					/* whatever we had before, with prefix we have username 
					   now */
					user=1;
				}

				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else if (a->type==STRIP_T) {
					if (a->elem[0].u.number>uri.user.len) {
						LM_WARN("too long strip asked; "
								" deleting username: %lu of <%.*s>\n",
								a->elem[0].u.number, uri.user.len, uri.user.s);
						len=0;
					} else if (a->elem[0].u.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s + a->elem[0].u.number;
						len=uri.user.len - a->elem[0].u.number;
					}
				} else if (a->type==STRIP_TAIL_T) {
					if (a->elem[0].u.number>uri.user.len) {
						LM_WARN("too long strip_tail asked;"
								" deleting username: %lu of <%.*s>\n",
								a->elem[0].u.number, uri.user.len, uri.user.s);
						len=0;
					} else if (a->elem[0].u.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s;
						len=uri.user.len - a->elem[0].u.number;
					}
				} else {
					tmp=uri.user.s;
					len=uri.user.len;
				}

				if (len){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					user=1; /* we have an user field so mark it */
				}

				if (a->type==SET_USERPASS_T) tmp=0;
				else tmp=uri.passwd.s;
				/* passwd */
				if (tmp){
					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* host */
				if (user || tmp){ /* add @ */
					if(crt+1>end) goto error_uri;
					*crt='@'; crt++;
				}
				if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else {
					tmp=uri.host.s;
					len = uri.host.len;
				}
				if (tmp){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* port */
				if (a->type==SET_HOSTPORT_T) tmp=0;
				else if (a->type==SET_PORT_T) {
					tmp=a->elem[0].u.s.s;
					len=a->elem[0].u.s.len;
				} else {
					tmp=uri.port.s;
					len = uri.port.len;
				}
				if (tmp && len>0){
					if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* params */
				tmp=uri.params.s;
				if (tmp){
					/* include in param string the starting ';' */
					len=uri.params.len+1;
					tmp--;
					if(crt+len+1>end) goto error_uri;
					/* if a maddr param is present, strip it out */
					if (uri.maddr.len &&
					(a->type==SET_HOSTPORT_T || a->type==SET_HOST_T)) {
						memcpy(crt,tmp,uri.maddr.s-tmp-1);
						crt+=uri.maddr.s-tmp-1;
						memcpy(crt,uri.maddr_val.s+uri.maddr_val.len,
							tmp+len-uri.maddr_val.s-uri.maddr_val.len);
						crt+=tmp+len-uri.maddr_val.s-uri.maddr_val.len;
					} else {
						memcpy(crt,tmp,len);crt+=len;
					}
				}
				/* headers */
				tmp=uri.headers.s;
				if (tmp){
					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
					*crt='?'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				*crt=0; /* null terminate the thing */
				/* copy it to the msg */
				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
				msg->new_uri.s=new_uri;
				msg->new_uri.len=crt-new_uri;
				msg->parsed_uri_ok=0;
				ret=1;
				break;
		case SET_DSTURI_T:
			script_trace("core", "set_dsturi", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in setdsturi() type %d\n",
							a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if(set_dst_uri(msg, &a->elem[0].u.s)!=0)
				ret = -1;
			else
				ret = 1;
			break;
		case SET_DSTHOST_T:
		case SET_DSTPORT_T:
			script_trace("core", (unsigned char) a->type == SET_DSTHOST_T ?
						 "set_dsturi" : "set_dstport", msg, a->line);
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in domain setting type %d\n",
							a->elem[0].type);
				ret=E_BUG;
				break;
			}

			tmp = msg->dst_uri.s;
			len = msg->dst_uri.len;

			if (tmp == NULL || len == 0) {
				LM_ERR("failure - null uri\n");
				ret = E_UNSPEC;
				break;
			}
			if (a->type == SET_DSTHOST_T &&
					(a->elem[0].u.s.s == NULL || a->elem[0].u.s.len == 0)) {
				LM_ERR("cannot set a null uri domain\n");
				break;
			}
			if (parse_uri(tmp, len, &uri)<0) {
				LM_ERR("bad uri <%.*s>, dropping packet\n", len, tmp);
				break;
			}
			new_uri=pkg_malloc(MAX_URI_SIZE);
			if (new_uri == NULL) {
				LM_ERR("memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			end=new_uri+MAX_URI_SIZE;
			crt=new_uri;
			len = (uri.user.len?uri.user.s:uri.host.s) - tmp;
			if (crt+len>end) goto error_uri;
			memcpy(crt,tmp,len);
			crt += len;
			/* user */
			tmp = uri.user.s;
			len = uri.user.len;
			if (tmp) {
				if (crt+len>end) goto error_uri;
				memcpy(crt,tmp,len);
				crt += len;
				user = 1;
			}
			/* passwd */
			tmp = uri.passwd.s;
			len = uri.passwd.len;
			if (user || tmp) {
				if (crt+len+1>end) goto error_uri;
				*crt++=':';
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* host */
			if (a->type==SET_DSTHOST_T) {
				tmp = a->elem[0].u.s.s;
				len = a->elem[0].u.s.len;
			} else {
				tmp = uri.host.s;
				len = uri.host.len;
			}
			if (tmp) {
				if (user) {
					if (crt+1>end) goto error_uri;
					*crt++='@';
				}
				if (crt+len+1>end) goto error_uri;
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* port */
			if (a->type==SET_DSTPORT_T) {
				tmp = a->elem[0].u.s.s;
				len = a->elem[0].u.s.len;
			} else {
				tmp = uri.port.s;
				len = uri.port.len;
			}
			if (tmp) {
				if (crt+len+1>end) goto error_uri;
				*crt++=':';
				memcpy(crt, tmp, len);
				crt += len;
			}
			/* params */
			tmp=uri.params.s;
			if (tmp){
				len=uri.params.len; if(crt+len+1>end) goto error_uri;
				*crt++=';';
				memcpy(crt,tmp,len);
				crt += len;
			}
			/* headers */
			tmp=uri.headers.s;
			if (tmp){
				len=uri.headers.len; if(crt+len+1>end) goto error_uri;
				*crt++='?';
				memcpy(crt,tmp,len);
				crt += len;
			}
			*crt=0; /* null terminate the thing */
			/* copy it to the msg */
			pkg_free(msg->dst_uri.s);
			msg->dst_uri.s=new_uri;
			msg->dst_uri.len=crt-new_uri;
			ret = 1;
			break;
		case RESET_DSTURI_T:
			script_trace("core", "reset_dsturi", msg, a->line) ;
			if(msg->dst_uri.s!=0)
				pkg_free(msg->dst_uri.s);
			msg->dst_uri.s = 0;
			msg->dst_uri.len = 0;
			ret = 1;
			break;
		case ISDSTURISET_T:
			script_trace("core", "isdsturiset", msg, a->line) ;
			if(msg->dst_uri.s==0 || msg->dst_uri.len<=0)
				ret = -1;
			else
				ret = 1;
			break;
		case IF_T:
			script_trace("core", "if", msg, a->line) ;
				/* if null expr => ignore if? */
				if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
					v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
					/* set return code to expr value */
					if (v<0 || (action_flags&ACT_FL_RETURN)
							|| (action_flags&ACT_FL_EXIT) ){
						if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/
							ret=0;
							return_code = 0;
							break;
						}else{
							LM_WARN("error in expression (l=%d)\n", a->line);
						}
					}
					
					ret=1;  /*default is continue */
					if (v>0) {
						if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){
							ret=run_action_list(
									(struct action*)a->elem[1].u.data,msg );
							return_code = ret;
						} else return_code = v;
					}else{
						if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){
							ret=run_action_list(
								(struct action*)a->elem[2].u.data,msg);
							return_code = ret;
						} else return_code = v;
					}
				}
			break;
		case WHILE_T:
			script_trace("core", "while", msg, a->line) ;
				/* if null expr => ignore if? */
				if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
					len = 0;
					while(1)
					{
						if(len++ >= max_while_loops)
						{
							LM_INFO("max while loops are encountered\n");
							break;
						}
						v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
						/* set return code to expr value */
						if (v<0 || (action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){
							if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
									|| (action_flags&ACT_FL_EXIT) ){
								ret=0;
								return_code = 0;
								break;
							}else{
								LM_WARN("error in expression (l=%d)\n",
										a->line);
							}
						}
					
						ret=1;  /*default is continue */
						if (v>0) {
							if ((a->elem[1].type==ACTIONS_ST)
									&&a->elem[1].u.data){
								ret=run_action_list(
									(struct action*)a->elem[1].u.data,msg );
								/* check if return was done */
								if ((action_flags&ACT_FL_RETURN)
								|| (action_flags&ACT_FL_EXIT) ){
									break;
								}
								return_code = ret;
							} else {
								/* we should not get here */
								return_code = v;
								break;
							}
						} else {
							/* condition was false */
							return_code = v;
							break;
						}
					}
				}
			break;
		case CACHE_STORE_T:
			script_trace("core", "cache_store", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[2].type!=STR_ST)) {
				LM_ALERT("BUG in cache_store() - third argument not of type"
						" string%d\n", a->elem[2].type );
				ret=E_BUG;
				break;
			}

			str val_s;

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			/* parse the value argument */
			pve = (pv_elem_t *)a->elem[2].u.data;
			if ( pv_printf_s(msg, pve, &val_s)!=0 || 
			val_s.len == 0 || val_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			/* get the expires value */
			if ( a->elem[3].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[3].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_store\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_store expires, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				expires = val.ri;
			}
			else
			if ( a->elem[3].type == NUMBER_ST )
			{
				expires = (int)a->elem[3].u.number;
			}

			ret = cachedb_store( &a->elem[0].u.s, &name_s, &val_s,expires);

			break;
		case CACHE_REMOVE_T:
			script_trace("core", "cache_remove", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_remove() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_remove() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}
			ret = cachedb_remove( &a->elem[0].u.s, &name_s);
			break;
		case CACHE_FETCH_T:
			script_trace("core", "cache_fetch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in cache_fetch() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			str aux = {0, 0};
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			ret = cachedb_fetch( &a->elem[0].u.s, &name_s, &aux);
			if(ret > 0)
			{
				val.rs = aux;
				val.flags = PV_VAL_STR;

				spec = (pv_spec_t*)a->elem[2].u.data;
				if (pv_set_value(msg, spec, 0, &val) < 0) {
					LM_ERR("cannot set the variable value\n");
					pkg_free(aux.s);
					return -1;
				}
				pkg_free(aux.s);
			}
			
			break;
		case CACHE_COUNTER_FETCH_T:
			script_trace("core", "cache_counter_fetch", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in cache_fetch() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			int aux_counter;
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			ret = cachedb_counter_fetch( &a->elem[0].u.s, &name_s, &aux_counter);
			if(ret > 0)
			{
				val.ri = aux_counter;
				val.flags = PV_TYPE_INT|PV_VAL_INT;

				spec = (pv_spec_t*)a->elem[2].u.data;
				if (pv_set_value(msg, spec, 0, &val) < 0) {
					LM_ERR("cannot set the variable value\n");
					pkg_free(aux.s);
					return -1;
				}
			}
			break;
		case CACHE_ADD_T:
			script_trace("core", "cache_add", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_add() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_add()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			int increment=0;

			/* get the increment value */
			if ( a->elem[2].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[2].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_add\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_add, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				increment = val.ri;
			}
			else if ( a->elem[2].type == NUMBER_ST )
			{
				increment = (int)a->elem[2].u.number;
			}

			expires = (int)a->elem[3].u.number;

			/* TODO - return the new value to script ? */
			ret = cachedb_add(&a->elem[0].u.s, &name_s, increment,expires,NULL);
			break;
		case CACHE_SUB_T:
			script_trace("core", "cache_sub", msg, a->line) ;
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_sub() - first argument not of"
						" type string [%d]\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}

			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_sub()  - second argument not of "
						"type string [%d]\n", a->elem[1].type );
				ret=E_BUG;
				break;
			}

			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			int decrement=0;

			/* get the increment value */
			if ( a->elem[2].type == SCRIPTVAR_ST )
			{
				spec = (pv_spec_t*)a->elem[2].u.data;
				memset(&val, 0, sizeof(pv_value_t));
				if(pv_get_spec_value(msg, spec, &val) < 0)
				{
					LM_DBG("Failed to get scriptvar value while executing cache_sub\n");
					ret=E_BUG;
					break;
				}
				if (!(val.flags&PV_VAL_INT))
				{
					LM_ERR("Wrong value for cache_sub, not an integer [%.*s]\n",
							val.rs.len, val.rs.s);
				}
				decrement = val.ri;
			}
			else if ( a->elem[2].type == NUMBER_ST )
			{
				decrement = (int)a->elem[2].u.number;
			}

			expires = (int)a->elem[3].u.number;

			/* TODO - return new value to script ? */
			ret = cachedb_sub(&a->elem[0].u.s, &name_s, decrement,expires,NULL);
			break;
		case CACHE_RAW_QUERY_T:
			if ((a->elem[0].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[0].type );
				ret=E_BUG;
				break;
			}
			if ((a->elem[1].type!=STR_ST)) {
				LM_ALERT("BUG in cache_fetch() %d\n",
					a->elem[1].type );
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data != NULL && 
				a->elem[2].type!=STR_ST){
				LM_ALERT("BUG in cache_raw_query() type %d\n",
						a->elem[2].type);
				ret=E_BUG;
				break;
			}
			/* parse the name argument */
			pve = (pv_elem_t *)a->elem[1].u.data;
			if ( pv_printf_s(msg, pve, &name_s)!=0 || 
			name_s.len == 0 || name_s.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}

			cdb_raw_entry **cdb_reply;
			int val_number=0,i,j;
			int key_number=0;
			pvname_list_t *cdb_res,*it;
			int_str avp_val;
			int_str avp_name;
			unsigned short avp_type;

			if (a->elem[2].u.data) {
				cdb_res = (pvname_list_t*)a->elem[2].u.data;
				for (it=cdb_res;it;it=it->next)
					val_number++;

				LM_DBG("The query expects %d results back\n",val_number);

				ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, &cdb_reply,val_number,&key_number);
				if (ret >= 0 && val_number > 0) {
					for (i=key_number-1; i>=0;i--) {
						it=cdb_res;
						for (j=0;j < val_number;j++) {
							avp_type = 0;
							if (pv_get_avp_name(msg,&it->sname.pvp,&avp_name.n,
								&avp_type) != 0) {
								LM_ERR("cannot get avp name [%d/%d]\n",i,j);
								goto next_avp;
							}
							
							switch (cdb_reply[i][j].type) {
								case CDB_INT:
									avp_val.n = cdb_reply[i][j].val.n; 
									break;
								case CDB_STR:
									avp_type |= AVP_VAL_STR;
									avp_val.s = cdb_reply[i][j].val.s;
									break;
								default:
									LM_WARN("Unknown type %d\n",cdb_reply[i][j].type);
									goto next_avp;
							}
							if (add_avp(avp_type,avp_name.n,avp_val) != 0) {
								LM_ERR("Unable to add AVP\n");
								free_raw_fetch(cdb_reply,val_number,key_number);
								return -1;
							}
next_avp:
							if (it) {
								it = it->next;
								if (it==NULL);
									break;
							}
						}
					}
					free_raw_fetch(cdb_reply,val_number,key_number);
				}
			}
			else
				ret = cachedb_raw_query( &a->elem[0].u.s, &name_s, NULL,0,NULL);
			break;
		case XDBG_T:
			script_trace("core", "xdbg", msg, a->line) ;
			if (a->elem[0].type == SCRIPTVAR_ELEM_ST)
			{
				if (xdbg(msg, a->elem[0].u.data, val.rs.s) < 0)
				{
					LM_ALERT("Cannot print message");
					break;
				}
			}
			else
			{
				LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type);
				ret=E_BUG;
			}
			break;
		case XLOG_T:
			script_trace("core", "xlog", msg, a->line) ;
			if (a->elem[1].u.data != NULL)
			{
				if (a->elem[1].type != SCRIPTVAR_ELEM_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type);
					ret=E_BUG;
					break;
				}
				if (a->elem[0].type != STR_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data) < 0)
				{
					LM_ALERT("Cannot print xlog debug message");
					break;
				}
			}
			else
			{
				if (a->elem[0].type != SCRIPTVAR_ELEM_ST)
				{
					LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
				if (xlog_1(msg,a->elem[0].u.data, val.rs.s) < 0)
				{
					LM_ALERT("Cannot print xlog debug message");
					break;
				}
			}

			break;
		case RAISE_EVENT_T:
			script_trace("core", "raise_event", msg, a->line) ;
			if (a->elem[0].type != NUMBER_ST) {
				LM_ERR("invalid event id\n");
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data) {
				/* three parameters specified */
				ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number,
						a->elem[1].u.data, a->elem[2].u.data);
			} else {
				/* two parameters specified */
				ret = evi_raise_script_event(msg, (event_id_t)a->elem[0].u.number,
						NULL, a->elem[1].u.data);
			}
			if (ret <= 0) {
				LM_ERR("cannot raise event\n");
				ret=E_UNSPEC;
				break;
			}
			break;
		case SUBSCRIBE_EVENT_T:
			script_trace("core", "subscribe_event", msg, a->line) ;
			if (a->elem[0].type != STR_ST || a->elem[1].type != STR_ST) {
				LM_ERR("BUG in subscribe arguments\n");
				ret=E_BUG;
				break;
			}
			if (a->elem[2].u.data) {
				if (a->elem[2].type != NUMBER_ST) {
					LM_ERR("BUG in subscribe expiration time\n");
					ret=E_BUG;
					break;
				} else {
					i = a->elem[2].u.number;
				}
			} else {
				i = 0;
			}

			name_s.s = a->elem[0].u.data;
			name_s.len = strlen(name_s.s);
			/* result should be the socket */
			result.s = a->elem[1].u.data;
			result.len = strlen(result.s);
			ret = evi_event_subscribe(name_s, result, i, 0);
			break;

		case CONSTRUCT_URI_T:
			script_trace("core", "construct_uri", msg, a->line) ;
			for (i=0;i<5;i++)
			{
				pve = (pv_elem_t *)a->elem[i].u.data;
				if (pve->spec.getf)
				{
					if ( pv_printf_s(msg, pve, &vals[i])!=0 || 
						vals[i].len == 0 || vals[i].s == NULL) 
					{
						LM_WARN("cannot get string for value\n");
						ret=E_BUG;
						return -1;
					}
				}
				else
					vals[i] = pve->text;
			}
			
			result.s = construct_uri(&vals[0],&vals[1],&vals[2],&vals[3],&vals[4],
					&result.len);

			if (result.s)
			{
				int_str res;
				int avp_name;
				unsigned short avp_type;

				spec = (pv_spec_t*)a->elem[5].u.data;
				if (pv_get_avp_name( msg, &(spec->pvp), &avp_name,
						&avp_type)!=0){
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.s = result;
				if (add_avp(AVP_VAL_STR|avp_type, avp_name, res)<0){
					LM_ERR("cannot add AVP\n");
					return -1;
				}
			}

			break;
		case GET_TIMESTAMP_T:
			script_trace("core", "get_timestamp", msg, a->line) ;
			if (get_timestamp(&sec,&usec) == 0) {
				int avp_name;
				int_str res;
				unsigned short avp_type;

				spec = (pv_spec_t*)a->elem[0].u.data;
				if (pv_get_avp_name(msg, &(spec->pvp), &avp_name,
						&avp_type) != 0) {
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.n = sec;
				if (add_avp(avp_type, avp_name, res) < 0) {
					LM_ERR("cannot add AVP\n");
					return -1;
				}

				spec = (pv_spec_t*)a->elem[1].u.data;
				if (pv_get_avp_name(msg, &(spec->pvp), &avp_name,
						&avp_type) != 0) {
					LM_CRIT("BUG in getting AVP name\n");
					return -1;
				}

				res.n = usec;
				if (add_avp(avp_type, avp_name, res) < 0) {
					LM_ERR("cannot add AVP\n");
					return -1;
				}
			} else {
				LM_ERR("failed to get time\n");
				return -1;
			}
			break;
		case SWITCH_T:
			script_trace("core", "switch", msg, a->line) ;
			if (a->elem[0].type!=SCRIPTVAR_ST){
				LM_ALERT("BUG in switch() type %d\n",
						a->elem[0].type);
				ret=E_BUG;
				break;
			}
			spec = (pv_spec_t*)a->elem[0].u.data;
			if(pv_get_spec_value(msg, spec, &val)!=0)
			{
				LM_ALERT("BUG - no value in switch()\n");
				ret=E_BUG;
				break;
			}

			/* get the value of pvar */
			if(a->elem[1].type!=ACTIONS_ST) {
				LM_ALERT("BUG in switch() actions\n");
				ret=E_BUG;
				break;
			}
			return_code=1;
			adefault = NULL;
			aitem = (struct action*)a->elem[1].u.data;
			cmatch=0;
			while(aitem)
			{
				if((unsigned char)aitem->type==DEFAULT_T)
					adefault=aitem;
				if(cmatch==0)
				{
					if(aitem->elem[0].type==STR_ST)
					{
						if(val.flags&PV_VAL_STR
								&& val.rs.len==aitem->elem[0].u.s.len
								&& strncasecmp(val.rs.s, aitem->elem[0].u.s.s,
									val.rs.len)==0)
							cmatch = 1;
					} else { /* number */
						if(val.flags&PV_VAL_INT && 
								val.ri==aitem->elem[0].u.number)
							cmatch = 1;
					}
				}
				if(cmatch==1)
				{
					if(aitem->elem[1].u.data)
					{
						return_code=run_action_list(
							(struct action*)aitem->elem[1].u.data, msg);
						if ((action_flags&ACT_FL_RETURN) ||
						(action_flags&ACT_FL_EXIT))
							break;
					}
					if(aitem->elem[2].u.number==1)
						break;
				}
				aitem = aitem->next;
			}
			if((cmatch==0) && (adefault!=NULL))
			{
				LM_DBG("switch: running default statement\n");
				if(adefault->elem[0].u.data)
					return_code=run_action_list(
						(struct action*)adefault->elem[0].u.data, msg);
			}
			ret=return_code;
			break;
		case MODULE_T:
			script_trace("module", ((cmd_export_t*)(a->elem[0].u.data))->name,
				msg, a->line) ;
			if ( (a->elem[0].type==CMD_ST) && a->elem[0].u.data ) {
				ret=((cmd_export_t*)(a->elem[0].u.data))->function(msg,
						 (char*)a->elem[1].u.data, (char*)a->elem[2].u.data,
						 (char*)a->elem[3].u.data, (char*)a->elem[4].u.data,
						 (char*)a->elem[5].u.data, (char*)a->elem[6].u.data);
			}else{
				LM_ALERT("BUG in module call\n");
			}
			break;
		case FORCE_RPORT_T:
			script_trace("core", "force_rport", msg, a->line) ;
			msg->msg_flags|=FL_FORCE_RPORT;
			ret=1; /* continue processing */
			break;
		case FORCE_LOCAL_RPORT_T:
			script_trace("core", "force_local_rport", msg, a->line) ;
			msg->msg_flags|=FL_FORCE_LOCAL_RPORT;
			ret=1; /* continue processing */
			break;
		case SET_ADV_ADDR_T:
			script_trace("core", "set_adv_addr", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in set_advertised_address() "
						"type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			str adv_addr;
			pve = (pv_elem_t *)a->elem[0].u.data;
			if ( pv_printf_s(msg, pve, &adv_addr)!=0 || 
			adv_addr.len == 0 || adv_addr.s == NULL) {
				LM_WARN("cannot get string for value\n");
				ret=E_BUG;
				break;
			}
			LM_DBG("adv address = [%.*s]\n",adv_addr.len,adv_addr.s);
			msg->set_global_address=adv_addr;
			ret=1; /* continue processing */
			break;
		case SET_ADV_PORT_T:
			script_trace("core", "set_adv_port", msg, a->line) ;
			if (a->elem[0].type!=STR_ST){
				LM_ALERT("BUG in set_advertised_port() "
						"type %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}

			msg->set_global_port=*((str*)a->elem[0].u.data);
			ret=1; /* continue processing */
			break;
#ifdef USE_TCP
		case FORCE_TCP_ALIAS_T:
			script_trace("core", "force_tcp_alias", msg, a->line) ;
			if ( msg->rcv.proto==PROTO_TCP
#ifdef USE_TLS
					|| msg->rcv.proto==PROTO_TLS
#endif
			   ){
				
				if (a->elem[0].type==NOSUBTYPE)	port=msg->via1->port;
				else if (a->elem[0].type==NUMBER_ST)
					port=(int)a->elem[0].u.number;
				else{
					LM_ALERT("BUG in force_tcp_alias"
							" port type %d\n", a->elem[0].type);
					ret=E_BUG;
					break;
				}
						
				if (tcpconn_add_alias(msg->rcv.proto_reserved1, port,
									msg->rcv.proto)!=0){
					LM_ERR("tcp alias failed\n");
					ret=E_UNSPEC;
					break;
				}
			}
#endif
			ret=1; /* continue processing */
			break;
		case FORCE_SEND_SOCKET_T:
			script_trace("core", "force_send_socket", msg, a->line) ;
			if (a->elem[0].type!=SOCKETINFO_ST){
				LM_ALERT("BUG in force_send_socket argument"
						" type: %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			msg->force_send_socket=(struct socket_info*)a->elem[0].u.data;
			ret=1; /* continue processing */
			break;
		case SERIALIZE_BRANCHES_T:
			script_trace("core", "serialize_branches", msg, a->line) ;
			if (a->elem[0].type!=NUMBER_ST){
				LM_ALERT("BUG in serialize_branches argument"
						" type: %d\n", a->elem[0].type);
				ret=E_BUG;
				break;
			}
			if (serialize_branches(msg,(int)a->elem[0].u.number)!=0) {
				LM_ERR("serialize_branches failed\n");
				ret=E_UNSPEC;
				break;
			}
			ret=1; /* continue processing */
			break;
		case NEXT_BRANCHES_T:
			script_trace("core", "next_branches", msg, a->line) ;
			if ((ret=next_branches(msg))<0) {
				LM_ERR("next_branches failed\n");
				ret=E_UNSPEC;
				break;
			}
			/* continue processing */
			break;
		case EQ_T:
		case COLONEQ_T:
		case PLUSEQ_T:
		case MINUSEQ_T:
		case DIVEQ_T:
		case MULTEQ_T:
		case MODULOEQ_T:
		case BANDEQ_T:
		case BOREQ_T:
		case BXOREQ_T:
			ret = do_assign(msg, a);
			break;
		case USE_BLACKLIST_T:
			script_trace("core", "use_blacklist", msg, a->line) ;
			mark_for_search((struct bl_head*)a->elem[0].u.data, 1);
			break;
		case UNUSE_BLACKLIST_T:
			script_trace("core", "unuse_blacklist", msg, a->line);
			mark_for_search((struct bl_head*)a->elem[0].u.data, 0);
			break;
		case PV_PRINTF_T:
			script_trace("core", "pv_printf", msg, a->line);
			ret = -1;
			spec = (pv_spec_p)a->elem[0].u.data;
			if(!pv_is_w(spec))
			{
				LM_ERR("read only PV in first parameter of pv_printf\n");
				goto error;
			}

			model = (pv_elem_p)a->elem[1].u.data;

			memset(&val, 0, sizeof(pv_value_t));
			if(pv_printf_s(msg, model, &val.rs)!=0)
			{
				LM_ERR("cannot eval second parameter\n");
				goto error;
			}
			val.flags = PV_VAL_STR;
			if(pv_set_value(msg, spec, EQ_T, &val)<0)
			{
				LM_ERR("setting PV failed\n");
				goto error;
			}
			
			ret = 1;
			break;
		case SCRIPT_TRACE_T:
			script_trace("core", "script_trace", msg, a->line);
			if (a->elem[0].type==NOSUBTYPE) {
				use_script_trace = 0;
			} else {
				
				use_script_trace = 1;
				
				if (a->elem[0].type != NUMBER_ST ||
					a->elem[1].type != SCRIPTVAR_ELEM_ST) {

					LM_ERR("BUG in use_script_trace() arguments\n");
					ret=E_BUG;
					break;
				}

				if (a->elem[2].type!=NOSUBTYPE) {
					script_trace_info = (char *)a->elem[2].u.data;
				} else {
					script_trace_info = NULL;
				}

				script_trace_log_level = (int)a->elem[0].u.number;
				script_trace_elem = *(pv_elem_p)a->elem[1].u.data;
			}

			break;
		default:
			LM_ALERT("BUG - unknown type %d\n", a->type);
			goto error;
	}

	if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T)
		return_code = ret;
/*skip:*/

	update_longest_action();
	return ret;

error:
	LM_ERR("error at line: %d\n", a->line);
	update_longest_action();
	return ret;
	
error_uri:
	LM_ERR("set*: uri too long\n");
	if (new_uri) pkg_free(new_uri);
	update_longest_action();
	return E_UNSPEC;
error_fwd_uri:
	update_longest_action();
	return ret;
}
Exemplo n.º 15
0
/* ret= 0! if action -> end of list(e.g DROP), 
      > 0 to continue processing next actions
   and <0 on error */
int do_action(struct action* a, struct sip_msg* msg)
{
	int ret;
	int v;
	union sockaddr_union* to;
	struct socket_info* send_sock;
	struct proxy_l* p;
	char* tmp;
	char *new_uri, *end, *crt;
	int len;
	int user;
	struct sip_uri uri, next_hop;
	struct sip_uri* u;
	unsigned short port;
	int proto;

	/* reset the value of error to E_UNSPEC so avoid unknowledgable
	   functions to return with errror (status<0) and not setting it
	   leaving there previous error; cache the previous value though
	   for functions which want to process it */
	prev_ser_error=ser_error;
	ser_error=E_UNSPEC;

	ret=E_BUG;
	switch ((unsigned char)a->type){
		case DROP_T:
				ret=0;
			break;
		case FORWARD_T:
#ifdef USE_TCP
		case FORWARD_TCP_T:
#endif
#ifdef USE_TLS
		case FORWARD_TLS_T:
#endif
		case FORWARD_UDP_T:

			if (a->type==FORWARD_UDP_T) proto=PROTO_UDP;
#ifdef USE_TCP
			else if (a->type==FORWARD_TCP_T) proto= PROTO_TCP;
#endif
#ifdef USE_TLS
			else if (a->type==FORWARD_TLS_T) proto= PROTO_TLS;
#endif
			else proto=msg->rcv.proto;
			if (a->p1_type==URIHOST_ST){
				/*parse uri*/

				if (msg->dst_uri.len) {
					ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop);
					u = &next_hop;
				} else {
					ret = parse_sip_msg_uri(msg);
					u = &msg->parsed_uri;
				}

				if (ret<0) {
					LOG(L_ERR, "ERROR: do_action: forward: bad_uri "
								" dropping packet\n");
					break;
				}
				
				switch (a->p2_type){
					case URIPORT_ST:
									port=u->port_no;
									break;
					case NUMBER_ST:
									port=a->p2.number;
									break;
					default:
							LOG(L_CRIT, "BUG: do_action bad forward 2nd"
										" param type (%d)\n", a->p2_type);
							ret=E_UNSPEC;
							goto error_fwd_uri;
				}
				switch(u->proto){
					case PROTO_NONE:
						proto=PROTO_UDP;
						break;
					case PROTO_UDP:
#ifdef USE_TCP
					case PROTO_TCP:
#endif
#ifdef USE_TLS
					case PROTO_TLS:
#endif
						proto=u->proto;
						break;
					default:
						LOG(L_ERR,"ERROR: do action: forward: bad uri"
								" transport %d\n", u->proto);
						ret=E_BAD_PROTO;
						goto error_fwd_uri;
				}
#ifdef USE_TLS
				if (u->secure){
					if (u->proto==PROTO_UDP){
						LOG(L_ERR, "ERROR: do_action: forward: secure uri"
								" incompatible with transport %d\n", u->proto);
						ret=E_BAD_PROTO;
						goto error_fwd_uri;
					}
					proto=PROTO_TLS;
				}
#endif
				/* create a temporary proxy*/
				p=mk_proxy(&u->host, port, proto);
				if (p==0){
					LOG(L_ERR, "ERROR:  bad host name in uri,"
							" dropping packet\n");
					ret=E_BAD_ADDRESS;
					goto error_fwd_uri;
				}
				ret=forward_request(msg, p, proto);
				/*free_uri(&uri); -- no longer needed, in sip_msg*/
				free_proxy(p); /* frees only p content, not p itself */
				pkg_free(p);
				if (ret>=0) ret=1;
			}else if ((a->p1_type==PROXY_ST) && (a->p2_type==NUMBER_ST)){
				ret=forward_request(msg,(struct proxy_l*)a->p1.data, proto);
				if (ret>=0) ret=1;
			}else{
				LOG(L_CRIT, "BUG: do_action: bad forward() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
			}
			break;
		case SEND_T:
		case SEND_TCP_T:
			if ((a->p1_type!= PROXY_ST)|(a->p2_type!=NUMBER_ST)){
				LOG(L_CRIT, "BUG: do_action: bad send() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			to=(union sockaddr_union*)
					pkg_malloc(sizeof(union sockaddr_union));
			if (to==0){
				LOG(L_ERR, "ERROR: do_action: "
							"memory allocation failure\n");
				ret=E_OUT_OF_MEM;
				break;
			}
			
			p=(struct proxy_l*)a->p1.data;
			
			if (p->ok==0){
				if (p->host.h_addr_list[p->addr_idx+1])
					p->addr_idx++;
				else 
					p->addr_idx=0;
				p->ok=1;
			}
			ret=hostent2su(	to, &p->host, p->addr_idx,
						(p->port)?p->port:SIP_PORT );
			if (ret==0){
				p->tx++;
				p->tx_bytes+=msg->len;
				if (a->type==SEND_T){
					/*udp*/
					send_sock=get_send_socket(to, PROTO_UDP);
					if (send_sock!=0){
						ret=udp_send(send_sock, msg->buf, msg->len, to);
					}else{
						ret=-1;
					}
				}
#ifdef USE_TCP
					else{
					/*tcp*/
					ret=tcp_send(PROTO_TCP, msg->buf, msg->len, to, 0);
				}
#endif
			}
			pkg_free(to);
			if (ret<0){
				p->errors++;
				p->ok=0;
			}else ret=1;
			
			break;
		case LOG_T:
			if ((a->p1_type!=NUMBER_ST)|(a->p2_type!=STRING_ST)){
				LOG(L_CRIT, "BUG: do_action: bad log() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			LOG(a->p1.number, a->p2.string);
			ret=1;
			break;

		/* jku -- introduce a new branch */
		case APPEND_BRANCH_T:
			if ((a->p1_type!=STRING_ST)) {
				LOG(L_CRIT, "BUG: do_action: bad append_branch_t %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			ret=append_branch( msg, a->p1.string, 
				a->p1.string ? strlen(a->p1.string):0 );
			break;

		/* jku begin: is_length_greater_than */
		case LEN_GT_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad len_gt type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			/* DBG("XXX: message length %d, max %d\n", 
				msg->len, a->p1.number ); */
			ret = msg->len >= a->p1.number ? 1 : -1;
			break;
		/* jku end: is_length_greater_than */
			
		/* jku - begin : flag processing */

		case SETFLAG_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad setflag() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			setflag( msg, a->p1.number );
			ret=1;
			break;

		case RESETFLAG_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad resetflag() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			resetflag( msg, a->p1.number );
			ret=1;
			break;
			
		case ISFLAGSET_T:
			if (a->p1_type!=NUMBER_ST) {
				LOG(L_CRIT, "BUG: do_action: bad isflagset() type %d\n",
					a->p1_type );
				ret=E_BUG;
				break;
			}
			if (!flag_in_range( a->p1.number )) {
				ret=E_CFG;
				break;
			}
			ret=isflagset( msg, a->p1.number );
			break;
		/* jku - end : flag processing */

		case ERROR_T:
			if ((a->p1_type!=STRING_ST)|(a->p2_type!=STRING_ST)){
				LOG(L_CRIT, "BUG: do_action: bad error() types %d, %d\n",
						a->p1_type, a->p2_type);
				ret=E_BUG;
				break;
			}
			LOG(L_NOTICE, "WARNING: do_action: error(\"%s\", \"%s\") "
					"not implemented yet\n", a->p1.string, a->p2.string);
			ret=1;
			break;
		case ROUTE_T:
			if (a->p1_type!=NUMBER_ST){
				LOG(L_CRIT, "BUG: do_action: bad route() type %d\n",
						a->p1_type);
				ret=E_BUG;
				break;
			}
			if ((a->p1.number>RT_NO)||(a->p1.number<0)){
				LOG(L_ERR, "ERROR: invalid routing table number in"
							"route(%lu)\n", a->p1.number);
				ret=E_CFG;
				break;
			}
			ret=((ret=run_actions(rlist[a->p1.number], msg))<0)?ret:1;
			break;
		case EXEC_T:
			if (a->p1_type!=STRING_ST){
				LOG(L_CRIT, "BUG: do_action: bad exec() type %d\n",
						a->p1_type);
				ret=E_BUG;
				break;
			}
			LOG(L_NOTICE, "WARNING: exec(\"%s\") not fully implemented,"
						" using dumb version...\n", a->p1.string);
			ret=system(a->p1.string);
			if (ret!=0){
				LOG(L_NOTICE, "WARNING: exec() returned %d\n", ret);
			}
			ret=1;
			break;
		case REVERT_URI_T:
			if (msg->new_uri.s) {
				pkg_free(msg->new_uri.s);
				msg->new_uri.len=0;
				msg->new_uri.s=0;
				msg->parsed_uri_ok=0; /* invalidate current parsed uri*/
			};
			ret=1;
			break;
		case SET_HOST_T:
		case SET_HOSTPORT_T:
		case SET_USER_T:
		case SET_USERPASS_T:
		case SET_PORT_T:
		case SET_URI_T:
		case PREFIX_T:
		case STRIP_T:
		case STRIP_TAIL_T:
				user=0;
				if (a->type==STRIP_T || a->type==STRIP_TAIL_T) {
					if (a->p1_type!=NUMBER_ST) {
						LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
							a->p1_type);
						break;
					}
				} else if (a->p1_type!=STRING_ST){
					LOG(L_CRIT, "BUG: do_action: bad set*() type %d\n",
							a->p1_type);
					ret=E_BUG;
					break;
				}
				if (a->type==SET_URI_T){
					if (msg->new_uri.s) {
							pkg_free(msg->new_uri.s);
							msg->new_uri.len=0;
					}
					msg->parsed_uri_ok=0;
					len=strlen(a->p1.string);
					msg->new_uri.s=pkg_malloc(len+1);
					if (msg->new_uri.s==0){
						LOG(L_ERR, "ERROR: do_action: memory allocation"
								" failure\n");
						ret=E_OUT_OF_MEM;
						break;
					}
					memcpy(msg->new_uri.s, a->p1.string, len);
					msg->new_uri.s[len]=0;
					msg->new_uri.len=len;
					
					ret=1;
					break;
				}
				if (msg->new_uri.s) {
					tmp=msg->new_uri.s;
					len=msg->new_uri.len;
				}else{
					tmp=msg->first_line.u.request.uri.s;
					len=msg->first_line.u.request.uri.len;
				}
				if (parse_uri(tmp, len, &uri)<0){
					LOG(L_ERR, "ERROR: do_action: bad uri <%s>, dropping"
								" packet\n", tmp);
					ret=E_UNSPEC;
					break;
				}
				
				new_uri=pkg_malloc(MAX_URI_SIZE);
				if (new_uri==0){
					LOG(L_ERR, "ERROR: do_action: memory allocation "
								" failure\n");
					ret=E_OUT_OF_MEM;
					break;
				}
				end=new_uri+MAX_URI_SIZE;
				crt=new_uri;
				/* begin copying */
				len=strlen("sip:"); if(crt+len>end) goto error_uri;
				memcpy(crt,"sip:",len);crt+=len;

				/* user */

				/* prefix (-jiri) */
				if (a->type==PREFIX_T) {
					tmp=a->p1.string;
					len=strlen(tmp); if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					/* whatever we had before, with prefix we have username 
					   now */
					user=1;
				}

				if ((a->type==SET_USER_T)||(a->type==SET_USERPASS_T)) {
					tmp=a->p1.string;
					len=strlen(tmp);
				} else if (a->type==STRIP_T) {
					if (a->p1.number>uri.user.len) {
						LOG(L_WARN, "Error: too long strip asked; "
									" deleting username: %lu of <%.*s>\n",
									a->p1.number, uri.user.len, uri.user.s );
						len=0;
					} else if (a->p1.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s + a->p1.number;
						len=uri.user.len - a->p1.number;
					}
				} else if (a->type==STRIP_TAIL_T) {
					if (a->p1.number>uri.user.len) {
						LOG(L_WARN, "WARNING: too long strip_tail asked; "
									" deleting username: %lu of <%.*s>\n",
									a->p1.number, uri.user.len, uri.user.s );
						len=0;
					} else if (a->p1.number==uri.user.len) {
						len=0;
					} else {
						tmp=uri.user.s;
						len=uri.user.len - a->p1.number;
					}
				} else {
					tmp=uri.user.s;
					len=uri.user.len;
				}

				if (len){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
					user=1; /* we have an user field so mark it */
				}

				if (a->type==SET_USERPASS_T) tmp=0;
				else tmp=uri.passwd.s;
				/* passwd */
				if (tmp){
					len=uri.passwd.len; if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* host */
				if (user || tmp){ /* add @ */
					if(crt+1>end) goto error_uri;
					*crt='@'; crt++;
				}
				if ((a->type==SET_HOST_T) ||(a->type==SET_HOSTPORT_T)) {
					tmp=a->p1.string;
					if (tmp) len = strlen(tmp);
					else len=0;
				} else {
					tmp=uri.host.s;
					len = uri.host.len;
				}
				if (tmp){
					if(crt+len>end) goto error_uri;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* port */
				if (a->type==SET_HOSTPORT_T) tmp=0;
				else if (a->type==SET_PORT_T) {
					tmp=a->p1.string;
					if (tmp) len = strlen(tmp);
					else len = 0;
				} else {
					tmp=uri.port.s;
					len = uri.port.len;
				}
				if (tmp){
					if(crt+len+1>end) goto error_uri;
					*crt=':'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* params */
				tmp=uri.params.s;
				if (tmp){
					len=uri.params.len; if(crt+len+1>end) goto error_uri;
					*crt=';'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				/* headers */
				tmp=uri.headers.s;
				if (tmp){
					len=uri.headers.len; if(crt+len+1>end) goto error_uri;
					*crt='?'; crt++;
					memcpy(crt,tmp,len);crt+=len;
				}
				*crt=0; /* null terminate the thing */
				/* copy it to the msg */
				if (msg->new_uri.s) pkg_free(msg->new_uri.s);
				msg->new_uri.s=new_uri;
				msg->new_uri.len=crt-new_uri;
				msg->parsed_uri_ok=0;
				ret=1;
				break;
		case IF_T:
				/* if null expr => ignore if? */
				if ((a->p1_type==EXPR_ST)&&a->p1.data){
					v=eval_expr((struct expr*)a->p1.data, msg);
					if (v<0){
						if (v==EXPR_DROP){ /* hack to quit on DROP*/
							ret=0;
							break;
						}else{
							LOG(L_WARN,"WARNING: do_action:"
										"error in expression\n");
						}
					}
					
					ret=1;  /*default is continue */
					if (v>0) {
						if ((a->p2_type==ACTIONS_ST)&&a->p2.data){
							ret=run_actions((struct action*)a->p2.data, msg);
						}
					}else if ((a->p3_type==ACTIONS_ST)&&a->p3.data){
							ret=run_actions((struct action*)a->p3.data, msg);
					}
				}
			break;
		case MODULE_T:
			if ( ((a->p1_type==CMDF_ST)&&a->p1.data)/*&&
					((a->p2_type==STRING_ST)&&a->p2.data)*/ ){
				ret=((cmd_function)(a->p1.data))(msg, (char*)a->p2.data,
													  (char*)a->p3.data);
			}else{
				LOG(L_CRIT,"BUG: do_action: bad module call\n");
			}
			break;
		case FORCE_RPORT_T:
			msg->msg_flags|=FL_FORCE_RPORT;
			ret=1; /* continue processing */
			break;
		case SET_ADV_ADDR_T:
			if (a->p1_type!=STR_ST){
				LOG(L_CRIT, "BUG: do_action: bad set_advertised_address() "
						"type %d\n", a->p1_type);
				ret=E_BUG;
				break;
			}
			msg->set_global_address=*((str*)a->p1.data);
			ret=1; /* continue processing */
			break;
		case SET_ADV_PORT_T:
			if (a->p1_type!=STR_ST){
				LOG(L_CRIT, "BUG: do_action: bad set_advertised_port() "
						"type %d\n", a->p1_type);
				ret=E_BUG;
				break;
			}
			msg->set_global_port=*((str*)a->p1.data);
			ret=1; /* continue processing */
			break;
		default:
			LOG(L_CRIT, "BUG: do_action: unknown type %d\n", a->type);
	}
/*skip:*/
	return ret;
	
error_uri:
	LOG(L_ERR, "ERROR: do_action: set*: uri too long\n");
	if (new_uri) pkg_free(new_uri);
	return E_UNSPEC;
error_fwd_uri:
	/*free_uri(&uri); -- not needed anymore, using msg->parsed_uri*/
	return ret;
}
Exemplo n.º 16
0
/* opens, binds and listens-on a control tcp socket
 * returns socket fd or -1 on error */
int init_tcpudp_sock(union sockaddr_union* sa_un, char* address, int port,
						enum socket_protos type)
{
	union sockaddr_union su;
	struct hostent* he;
	int s;
	int optval;
	
	s=-1;
	if ((type!=UDP_SOCK) && (type!=TCP_SOCK)){
		LOG(L_CRIT, "BUG: init_tcpudp_sock called with bad type: %d\n",
				type);
		goto error;
	}
	memset(&su, 0, sizeof (su));
	/* if no address specified, or address=='*', listen on all
	 * ipv4 addresses */
	if ((address==0)||((*address)==0)||((*address=='*') && (*(address+1)==0))){
		su.sin.sin_family=AF_INET;
		su.sin.sin_port=htons(port);
		su.sin.sin_addr.s_addr=INADDR_ANY;
#ifdef HAVE_SOCKADDR_SA_LEN
		su.sin.sin_len=sizeof(struct sockaddr_in);
#endif
	}else{
		he=resolvehost(address);
		if (he==0){
			LOG(L_ERR, "ERROR: init_tcpudp_sock: bad address %s\n", address);
			goto error;
		}
		if (hostent2su(&su, he, 0, port)==-1) goto error;
	}
	s=socket(AF2PF(su.s.sa_family), (type==TCP_SOCK)?SOCK_STREAM:SOCK_DGRAM,0);
	if (s==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: cannot create tcp socket:"
				" %s [%d]\n", strerror(errno), errno);
		goto error;
	}
	/* REUSEADDR */
	optval=1;
	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: setsockopt: %s [%d]\n", 
				strerror(errno), errno);
		/* continue */
	}
	/* tos */
	optval=IPTOS_LOWDELAY;
	if (setsockopt(s, IPPROTO_IP, IP_TOS, (void*)&optval,sizeof(optval)) ==-1){
		LOG(L_WARN, "WARNING: init_tcpudp_sock: setsockopt tos: %s\n",
				strerror(errno));
		/* continue since this is not critical */
	}
	if (set_non_blocking(s)==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: set non blocking failed\n");
	}
	
	if (bind(s, &su.s, sockaddru_len(su))==-1){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: bind: %s [%d]\n",
				strerror(errno), errno);
		goto error;
	}
	if ((type==TCP_SOCK) && (listen(s, 128)==-1)){
		LOG(L_ERR, "ERROR: init_tcpudp_sock: listen: %s [%d]\n",
				strerror(errno), errno);
		goto error;
	}
	*sa_un=su;
	return s;
error:
	if (s!=-1) close(s);
	return -1;
}
Exemplo n.º 17
0
int add_node_info(node_info_t **new_info, cluster_info_t **cl_list, int *int_vals,
					char **str_vals)
{
	char *host;
	int hlen, port;
	int proto;
	struct hostent *he;
	int cluster_id;
	cluster_info_t *cluster = NULL;
	struct timeval t;
	str st;
	str seed_flag = str_init(SEED_NODE_FLAG_STR);

	cluster_id = int_vals[INT_VALS_CLUSTER_ID_COL];
	/* new_info is checked whether it is initialized or not in case of error,
	 * so we have to initialize it as soon as possible */
	*new_info = NULL;

	for (cluster = *cl_list; cluster && cluster->cluster_id != cluster_id;
		cluster = cluster->next) ;

	if (!cluster) {
		cluster = shm_malloc(sizeof *cluster);
		if (!cluster) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		memset(cluster, 0, sizeof *cluster);

		cluster->cluster_id = cluster_id;
		cluster->next = *cl_list;
		if ((cluster->lock = lock_alloc()) == NULL) {
			LM_CRIT("Failed to allocate lock\n");
			goto error;
		}
		if (!lock_init(cluster->lock)) {
			lock_dealloc(cluster->lock);
			LM_CRIT("Failed to init lock\n");
			goto error;
		}
		*cl_list = cluster;
	}

	*new_info = shm_malloc(sizeof **new_info);
	if (!*new_info) {
		LM_ERR("no more shm memory\n");
		goto error;
	}
	memset(*new_info, 0, sizeof **new_info);

	(*new_info)->flags = 0;

	(*new_info)->id = int_vals[INT_VALS_ID_COL];
	(*new_info)->node_id = int_vals[INT_VALS_NODE_ID_COL];
	if (int_vals[INT_VALS_STATE_COL])
		(*new_info)->flags |= NODE_STATE_ENABLED;
	else
		(*new_info)->flags &= ~NODE_STATE_ENABLED;

	if (int_vals[INT_VALS_NODE_ID_COL] != current_id)
		(*new_info)->link_state = LS_RESTART_PINGING;
	else
		(*new_info)->link_state = LS_UP;

	if (str_vals[STR_VALS_DESCRIPTION_COL] &&
		strlen(str_vals[STR_VALS_DESCRIPTION_COL]) != 0) {
		(*new_info)->description.len = strlen(str_vals[STR_VALS_DESCRIPTION_COL]);
		(*new_info)->description.s =
			shm_malloc((*new_info)->description.len * sizeof(char));
		if ((*new_info)->description.s == NULL) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		memcpy((*new_info)->description.s, str_vals[STR_VALS_DESCRIPTION_COL],
			(*new_info)->description.len);
	} else {
		(*new_info)->description.s = NULL;
		(*new_info)->description.len = 0;
	}

	if (str_vals[STR_VALS_SIP_ADDR_COL] &&
		strlen(str_vals[STR_VALS_SIP_ADDR_COL]) != 0) {
		(*new_info)->sip_addr.len = strlen(str_vals[STR_VALS_SIP_ADDR_COL]);
		(*new_info)->sip_addr.s = shm_malloc((*new_info)->sip_addr.len * sizeof(char));
		if ((*new_info)->sip_addr.s == NULL) {
			LM_ERR("no more shm memory\n");
			goto error;
		}
		memcpy((*new_info)->sip_addr.s, str_vals[STR_VALS_SIP_ADDR_COL],
			(*new_info)->sip_addr.len);
	} else {
		(*new_info)->sip_addr.s = NULL;
		(*new_info)->sip_addr.len = 0;
	}

	if (str_vals[STR_VALS_FLAGS_COL] &&
		strlen(str_vals[STR_VALS_FLAGS_COL]) != 0)
		if (memcmp(str_vals[STR_VALS_FLAGS_COL], seed_flag.s, seed_flag.len) == 0)
			(*new_info)->flags |= NODE_IS_SEED;

	if (str_vals[STR_VALS_URL_COL] == NULL) {
		LM_ERR("no url specified in DB\n");
		return 1;
	}
	(*new_info)->url.len = strlen(str_vals[STR_VALS_URL_COL]);
	(*new_info)->url.s = shm_malloc(strlen(str_vals[STR_VALS_URL_COL]) * sizeof(char));
	if (!(*new_info)->url.s) {
		LM_ERR("no more shm memory\n");
		goto error;
	}
	memcpy((*new_info)->url.s, str_vals[STR_VALS_URL_COL], (*new_info)->url.len);

	if (int_vals[INT_VALS_NODE_ID_COL] != current_id) {
		if (parse_phostport((*new_info)->url.s, (*new_info)->url.len, &host, &hlen,
			&port, &proto) < 0) {
			LM_ERR("Bad URL!\n");
			return 1;
		}

		if (proto == PROTO_NONE)
			proto = clusterer_proto;
		if (proto != clusterer_proto) {
			LM_ERR("Clusterer currently supports only BIN protocol, but node: %d "
				"has proto=%d\n", int_vals[INT_VALS_NODE_ID_COL], proto);
			return 1;
		}

		st.s = host;
		st.len = hlen;
		he = sip_resolvehost(&st, (unsigned short *) &port,
			(unsigned short *)&proto, 0, 0);
		if (!he) {
			LM_ERR("Cannot resolve host: %.*s\n", hlen, host);
			return 1;
		}

		hostent2su(&((*new_info)->addr), he, 0, port);

		t.tv_sec = 0;
		t.tv_usec = 0;
		(*new_info)->last_ping = t;
		(*new_info)->last_pong = t;
	}

	(*new_info)->priority = int_vals[INT_VALS_PRIORITY_COL];

	(*new_info)->no_ping_retries = int_vals[INT_VALS_NO_PING_RETRIES_COL];

	(*new_info)->cluster = cluster;

	(*new_info)->ls_seq_no = -1;
	(*new_info)->top_seq_no = -1;
	(*new_info)->ls_timestamp = 0;
	(*new_info)->top_timestamp = 0;

	(*new_info)->sp_info = shm_malloc(sizeof(struct node_search_info));
	if (!(*new_info)->sp_info) {
		LM_ERR("no more shm memory\n");
		goto error;
	}
	(*new_info)->sp_info->node = *new_info;

	if (int_vals[INT_VALS_NODE_ID_COL] != current_id) {
		(*new_info)->next = cluster->node_list;
		cluster->node_list = *new_info;
		cluster->no_nodes++;
		if (cluster->no_nodes > MAX_NO_NODES) {
			LM_ERR("Defined: %d nodes for cluster: %d, maximum number of nodes "
				"supported(%d) exceeded\n", cluster->no_nodes,
				cluster->cluster_id, MAX_NO_NODES);
			goto error;
		}
	} else {
		(*new_info)->next = NULL;
		cluster->current_node = *new_info;
	}

	if (((*new_info)->lock = lock_alloc()) == NULL) {
		LM_CRIT("Failed to allocate lock\n");
		goto error;
	}
	if (!lock_init((*new_info)->lock)) {
		lock_dealloc((*new_info)->lock);
		LM_CRIT("Failed to init lock\n");
		goto error;
	}

	return 0;
error:
	if (*new_info) {
		if ((*new_info)->sip_addr.s)
			shm_free((*new_info)->sip_addr.s);

		if ((*new_info)->description.s)
			shm_free((*new_info)->description.s);

		if ((*new_info)->url.s)
			shm_free((*new_info)->url.s);

		if ((*new_info)->sp_info)
			shm_free((*new_info)->sp_info);

		shm_free(*new_info);
	}
	return -1;
}
Exemplo n.º 18
0
static void
timer(unsigned int ticks, void *param)
{
	int rval;
	void *buf, *cp;
	str c;
	struct sip_uri curi;
	union sockaddr_union to;
	struct hostent* he;
	struct socket_info* send_sock;

	buf = NULL;
	if (cblen > 0) {
		buf = pkg_malloc(cblen);
		if (buf == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n");
			return;
		}
	}
	rval = get_all_ucontacts(buf, cblen);
	if (rval > 0) {
		if (buf != NULL)
			pkg_free(buf);
		cblen = rval * 2;
		buf = pkg_malloc(cblen);
		if (buf == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: out of memory\n");
			return;
		}
		rval = get_all_ucontacts(buf, cblen);
		if (rval != 0) {
			pkg_free(buf);
			return;
		}
	}

	if (buf == NULL)
		return;

	cp = buf;
	while (1) {
		memcpy(&(c.len), cp, sizeof(c.len));
		if (c.len == 0)
			break;
		c.s = (char*)cp + sizeof(c.len);
		cp =  (char*)cp + sizeof(c.len) + c.len;
		if (parse_uri(c.s, c.len, &curi) < 0) {
			LOG(L_ERR, "ERROR: nathelper::timer: can't parse contact uri\n");
			continue;
		}
		if (curi.proto != PROTO_UDP && curi.proto != PROTO_NONE)
			continue;
		if (curi.port_no == 0)
			curi.port_no = SIP_PORT;
		he = sip_resolvehost(&curi.host, &curi.port_no, PROTO_UDP);
		if (he == NULL){
			LOG(L_ERR, "ERROR: nathelper::timer: can't resolve_hos\n");
			continue;
		}
		hostent2su(&to, he, 0, curi.port_no);
		send_sock = get_send_socket(&to, PROTO_UDP);
		if (send_sock == NULL) {
			LOG(L_ERR, "ERROR: nathelper::timer: can't get sending socket\n");
			continue;
		}
		udp_send(send_sock, (char *)sbuf, sizeof(sbuf), &to);
	}
	pkg_free(buf);
}
Exemplo n.º 19
0
/*
 * This is the parsing function
 * The socket grammar should be:
 * 		 ip ':' port '/optional/path' ':' method
 */
static evi_reply_sock* xmlrpc_parse(str socket)
{
	evi_reply_sock *sock = NULL;
	unsigned short port = 0;
	char *p = NULL;
	str host, path=str_init(NULL);
	struct hostent *hentity;
	int len;
	struct xmlrpc_sock_param *params;

	int http_buf_len=0;

	if (!socket.len || !socket.s) {
		LM_ERR("no socket specified\n");
		return NULL;
	}

	if (!(params=shm_malloc(sizeof(struct xmlrpc_sock_param)))) {
		LM_ERR("no more pkg mem!\n");
		return NULL;
	}
	memset(params, 0, sizeof(struct xmlrpc_sock_param));

	/* extract host */
	host.s = socket.s;
	p = memchr(socket.s, COLON_C, socket.len);
	if (!p || p == socket.s) {
		LM_ERR("port not specified <%.*s>\n", socket.len, socket.s);
		return NULL;
	}
	host.len = p - socket.s;

	/* used to resolve host */
	*p = '\0';
	/* skip colon */
	socket.s += host.len + 1;
	socket.len -= host.len + 1;

	LM_DBG("host is %.*s - remains <%.*s>[%d]\n", host.len, host.s,
			socket.len, socket.s, socket.len);

	if (!socket.len || *socket.s == '\0') {
		LM_ERR("invalid port number\n");
		return NULL;
	}

	p = memchr(socket.s, COLON_C, socket.len);
	if (!p || p == socket.s) {
		LM_ERR("method not specified <%.*s>\n", socket.len, socket.s);
		return NULL;
	}

	port = str2s(socket.s, p - socket.s, 0);
	if (port == 0) {
		/* most probably we've got path */
		if ((path.s=(q_memchr(socket.s, SLASH_C, p-socket.s)))==NULL) {
			LM_ERR("malformed port: %.*s\n",(int)(p - socket.s), socket.s);
			return NULL;
		} else {
			port=str2s(socket.s, path.s-socket.s, 0);
			if (port == 0) {
				LM_ERR("malformed port: %.*s\n",(int)(p - socket.s), socket.s);
				return NULL;
			}

			path.len = p - path.s;

			socket.len -= ((path.s+path.len)-socket.s);
			socket.s = path.s+path.len;
		}

		/* will use this later for allocation */
		http_buf_len=LENOF(XMLRPC_HTTP_METHOD) +  path.len +
			LENOF(XMLRPC_HTTP_PROTO_HOST);
	}

	/* jump over ':' */
	socket.len = socket.len - (p - socket.s + 1);
	socket.s = p + 1;

	LM_DBG("port is %hu - remains <%.*s>[%d]\n",
			port, socket.len, socket.s, socket.len);

	if (socket.len <= 0 || *socket.s == '\0') {
		LM_ERR("invalid method name\n");
		return NULL;
	}

	len = sizeof(evi_reply_sock) + host.len
		+ sizeof(struct xmlrpc_sock_param)
		+ socket.len /* this is method */+ http_buf_len;
	sock = shm_malloc(len);
	if (!sock) {
		LM_ERR("no more memory for socket\n");
		return NULL;
	}

	memset(sock, 0, len);
	/* only UDP has port */
	sock->flags = EVI_PORT;
	sock->port = port;

	/* also build sockaddr */
	hentity = resolvehost(host.s, 0);
	if (!hentity) {
		LM_ERR("cannot resolve host %s\n", host.s);
		goto error;
	}
	if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){
		LM_ERR("failed to resolve %s\n", host.s);
		goto error;
	}
	sock->flags |= EVI_SOCKET;

	/* address */
	sock->address.s = (char*)(sock+1);
	sock->address.len = host.len;
	memcpy(sock->address.s, host.s, host.len);
	sock->flags |= EVI_ADDRESS;



	/* copy parameters: path and method */
	params = (struct xmlrpc_sock_param*)(sock->address.s + host.len);
	params->method.s = (char*)(params+1);

	memcpy(params->method.s, socket.s, socket.len);
	params->method.len = socket.len;

	if (http_buf_len) {
		/* build only once; not for every message */
		params->first_line.s = (char*)(params->method.s+socket.len);

		memcpy(params->method.s, socket.s, socket.len);

		params->first_line.len = 0;

		memcpy(params->first_line.s,
				XMLRPC_HTTP_METHOD, LENOF(XMLRPC_HTTP_METHOD));
		params->first_line.len = LENOF(XMLRPC_HTTP_METHOD);

		memcpy(params->first_line.s+params->first_line.len, path.s, path.len);
		params->first_line.len += path.len;

		memcpy(params->first_line.s+params->first_line.len, XMLRPC_HTTP_PROTO_HOST,
				LENOF(XMLRPC_HTTP_PROTO_HOST));
		params->first_line.len += LENOF(XMLRPC_HTTP_PROTO_HOST);
	} else {
		params->first_line.s = XMLRPC_HTTP_CONST;
		params->first_line.len = LENOF(XMLRPC_HTTP_CONST);
	}



	sock->flags |= EVI_PARAMS;

	/* needs expire */
	sock->flags |= EVI_EXPIRE|XMLRPC_FLAG;

	sock->params= params;

	return sock;
error:
	if (sock)
		shm_free(sock);
	return NULL;
}
Exemplo n.º 20
0
int jsonrpc_dgram_mod_init(void)
{
	unsigned int port_no;
	int n;
	struct stat filestat;
	struct hostent *host;
	char *p, *host_s;
	str port_str;
	int len;
	int sep;

	/* checking the mi_socket module param */
	LM_DBG("testing socket existance...\n");

	if( jsonrpc_dgram_socket==NULL || *jsonrpc_dgram_socket == 0) {
		LM_ERR("no DATAGRAM_ socket configured\n");
		return -1;
	}

	LM_DBG("the socket's name/address is %s\n", jsonrpc_dgram_socket);

	memset( &jsonrpc_dgram_addr, 0, sizeof(jsonrpc_dgram_sockaddr_t) );

	if(strlen(jsonrpc_dgram_socket)<6) {
		LM_ERR("lenght of socket address is too short: %s\n",
				jsonrpc_dgram_socket);
		return -1;
	}
	if(strncmp(jsonrpc_dgram_socket, "udp:", 4) == 0) {
		/*for an UDP socket*/
		LM_DBG("udp socket provided\n");
		/*separate proto and host */
		p = jsonrpc_dgram_socket+4;
		if( (*(p)) == '\0') {
			LM_ERR("malformed ip address\n");
			return -1;
		}
		host_s=p;
		LM_DBG("remaining address after separating the protocol is %s\n", p);

		if( (p = strrchr(p+1, ':')) == 0 ) {
			LM_ERR("no port specified\n");
			return -1;
		}

		/*the address contains a port number*/
		*p = '\0';
		p++;
		port_str.s = p;
		port_str.len = strlen(p);
		LM_DBG("the port string is %s\n", p);
		if(str2int(&port_str, &port_no) != 0 ) {
			LM_ERR("there is not a valid number port\n");
			return -1;
		}
		*p = '\0';
		if (port_no<1024  || port_no>65535)
		{
			LM_ERR("invalid port number; must be in [1024,65535]\n");
			return -1;
		}

		if(! (host = resolvehost(host_s)) ) {
			LM_ERR("failed to resolve %s\n", host_s);
			return -1;
		}
		LM_DBG("the ip is %s\n",host_s);
		if(hostent2su( &(jsonrpc_dgram_addr.udp_addr), host, 0, port_no ) !=0) {
			LM_ERR("failed to resolve %s\n", jsonrpc_dgram_socket);
			return -1;
		}
		jsonrpc_dgram_socket_domain = host->h_addrtype;
		goto done;
	}
	/* in case of a Unix socket*/
	LM_DBG("UNIX socket provided\n");

	if(*jsonrpc_dgram_socket != '/') {
		if(runtime_dir!=NULL && *runtime_dir!=0) {
			len = strlen(runtime_dir);
			sep = 0;
			if(runtime_dir[len-1]!='/') {
				sep = 1;
			}
			len += sep + strlen(jsonrpc_dgram_socket);
			p = pkg_malloc(len + 1);
			if(p==NULL) {
				LM_ERR("no more pkg\n");
				return -1;
			}
			strcpy(p, runtime_dir);
			if(sep) strcat(p, "/");
			strcat(p, jsonrpc_dgram_socket);
			jsonrpc_dgram_socket = p;
			LM_DBG("unix socket path is [%s]\n", jsonrpc_dgram_socket);
		}
	}

	n=stat(jsonrpc_dgram_socket, &filestat);
	if( n==0) {
		LM_INFO("the socket %s already exists, trying to delete it...\n",
				jsonrpc_dgram_socket);
		if(config_check==0) {
			if (unlink(jsonrpc_dgram_socket)<0) {
				LM_ERR("cannot delete old socket: %s\n", strerror(errno));
				return -1;
			}
		}
	} else if (n<0 && errno!=ENOENT) {
		LM_ERR("socket stat failed:%s\n", strerror(errno));
		return -1;
	}

	/* check mi_unix_socket_mode */
	if(!jsonrpc_dgram_unix_socket_mode) {
		LM_WARN("cannot specify jsonrpc_dgram_unix_socket_mode = 0,"
				" forcing it to rw-------\n");
		jsonrpc_dgram_unix_socket_mode = S_IRUSR| S_IWUSR;
	}

	if (jsonrpc_dgram_unix_socket_uid_s) {
		if (user2uid(&jsonrpc_dgram_unix_socket_uid,
					&jsonrpc_dgram_unix_socket_gid,
					jsonrpc_dgram_unix_socket_uid_s)<0) {
			LM_ERR("bad user name %s\n", jsonrpc_dgram_unix_socket_uid_s);
			return -1;
		}
	}

	if (jsonrpc_dgram_unix_socket_gid_s) {
		if (group2gid(&jsonrpc_dgram_unix_socket_gid,
					jsonrpc_dgram_unix_socket_gid_s)<0) {
			LM_ERR("bad group name %s\n", jsonrpc_dgram_unix_socket_gid_s);
			return -1;
		}
	}

	/*create the unix socket address*/
	jsonrpc_dgram_addr.unix_addr.sun_family = AF_LOCAL;
	if(strlen(jsonrpc_dgram_socket)
			>= sizeof(jsonrpc_dgram_addr.unix_addr.sun_path)-1) {
		LM_ERR("socket path is too long\n");
		return -1;
	}
	memcpy(jsonrpc_dgram_addr.unix_addr.sun_path,
			jsonrpc_dgram_socket, strlen(jsonrpc_dgram_socket));

done:
	/* add space for extra processes */
	register_procs(jsonrpc_dgram_workers);
	/* add child to update local config framework structures */
	cfg_register_child(jsonrpc_dgram_workers);

	return 0;
}
Exemplo n.º 21
0
/*
 * This is the parsing function
 * The socket grammar should be:
 * 		 ip ':' port ':' method
 */
static evi_reply_sock* xmlrpc_parse(str socket)
{
	evi_reply_sock *sock = NULL;
	unsigned short port = 0;
	char *p = NULL;
	str host, *method;
	struct hostent *hentity;
	int len;

	if (!socket.len || !socket.s) {
		LM_ERR("no socket specified\n");
		return NULL;
	}

	/* extract host */
	host.s = socket.s;
	p = memchr(socket.s, COLON_C, socket.len);
	if (!p || p == socket.s) {
		LM_ERR("port not specified <%.*s>\n", socket.len, socket.s);
		return NULL;
	}
	host.len = p - socket.s;
	/* used to resolve host */
	*p = '\0';
	/* skip colon */
	socket.s += host.len + 1;
	socket.len -= host.len + 1;

	LM_DBG("host is %.*s - remains <%.*s>[%d]\n", host.len, host.s,
			socket.len, socket.s, socket.len);
	
	if (!socket.len || *socket.s == '\0') {
		LM_ERR("invalid port number\n");
		return NULL;
	}

	p = memchr(socket.s, COLON_C, socket.len);
	if (!p || p == socket.s) {
		LM_ERR("method not specified <%.*s>\n", socket.len, socket.s);
		return NULL;
	}
	port = str2s(socket.s, p - socket.s, 0);
	if (port == 0) {
		LM_DBG("malformed port: %.*s\n",(int)(p - socket.s), socket.s);
		return NULL;
	}

	/* skip colon */
	socket.len = socket.len - (p - socket.s + 1);
	socket.s = p + 1;

	LM_DBG("port is %hu - remains <%.*s>[%d]\n",
			port, socket.len, socket.s, socket.len);

	if (socket.len <= 0 || *socket.s == '\0') {
		LM_ERR("invalid method name\n");
		return NULL;
	}
	
	LM_DBG("method is %.*s[%d]\n", socket.len, socket.s, socket.len);

	len = sizeof(evi_reply_sock) - sizeof(void*) + sizeof(str) + 
		host.len + socket.len;
	sock = shm_malloc(len);
	if (!sock) {
		LM_ERR("no more memory for socket\n");
		return NULL;
	}

	memset(sock, 0, len);
	/* only UDP has port */
	sock->flags = EVI_PORT;
	sock->port = port;

	/* also build sockaddr */
	hentity = resolvehost(host.s, 0);
	if (!hentity) {
		LM_ERR("cannot resolve host %s\n", host.s);
		goto error;
	}
	if(hostent2su(&sock->src_addr.udp_addr, hentity, 0, port)){
		LM_ERR("failed to resolve %s\n", host.s);
		goto error;
	}
	sock->flags |= EVI_SOCKET;

	/* copy method  - this should point to same address as params*/
	method = (str *) &sock->params;
	method->s = (char *) (method + 1);
	method->len = socket.len;
	memcpy(method->s, socket.s, socket.len);
	sock->flags |= EVI_PARAMS;

	/* address should point below method name */
	sock->address.s = method->s + method->len;
	sock->address.len = host.len;
	memcpy(sock->address.s, host.s, host.len);
	sock->flags |= EVI_ADDRESS;

	/* needs expire */
	sock->flags |= EVI_EXPIRE|XMLRPC_FLAG;

	return sock;
error:
	if (sock)
		shm_free(sock);
	return NULL;
}
Exemplo n.º 22
0
/* introduce a new uac to transaction; returns its branch id (>=0)
   or error (<0); it doesn't send a message yet -- a reply to it
   might interfere with the processes of adding multiple branches
*/
static int add_uac( struct cell *t, struct sip_msg *request, str *uri,
		str* next_hop, unsigned int bflags, str* path, struct proxy_l *proxy)
{
	unsigned short branch;
	struct sip_msg_body *body_clone=NO_BODY_CLONE_MARKER;
	int do_free_proxy;
	int ret;

	branch=t->nr_of_outgoings;
	if (branch==MAX_BRANCHES) {
		LM_ERR("maximum number of branches exceeded\n");
		ret=E_CFG;
		goto error;
	}

	/* check existing buffer -- rewriting should never occur */
	if (t->uac[branch].request.buffer.s) {
		LM_CRIT("buffer rewrite attempt\n");
		ret=ser_error=E_BUG;
		goto error;
	}

	/* set proper RURI to request to reflect the branch */
	request->new_uri=*uri;
	request->parsed_uri_ok=0;
	request->dst_uri=*next_hop;
	request->path_vec=*path;
	request->ruri_bflags=bflags;

	if ( pre_print_uac_request( t, branch, request, &body_clone)!= 0 ) {
		ret = -1;
		goto error01;
	}

	/* check DNS resolution */
	if (proxy){
		do_free_proxy = 0;
	}else {
		proxy=uri2proxy( request->dst_uri.len ?
			&request->dst_uri:&request->new_uri,
			request->force_send_socket ?
				request->force_send_socket->proto : PROTO_NONE );
		if (proxy==0)  {
			ret=E_BAD_ADDRESS;
			goto error01;
		}
		do_free_proxy = 1;
	}

	msg_callback_process(request, REQ_PRE_FORWARD, (void *)proxy);

	if ( !(t->flags&T_NO_DNS_FAILOVER_FLAG) ) {
		t->uac[branch].proxy = shm_clone_proxy( proxy , do_free_proxy );
		if (t->uac[branch].proxy==NULL) {
			ret = E_OUT_OF_MEM;
			goto error02;
		}
	}

	/* use the first address */
	hostent2su( &t->uac[branch].request.dst.to,
		&proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT);
	t->uac[branch].request.dst.proto = proxy->proto;

	/* do print of the uac request */
	if ( update_uac_dst( request, &t->uac[branch] )!=0) {
		ret = ser_error;
		goto error02;
	}

	/* things went well, move ahead */
	t->uac[branch].uri.s=t->uac[branch].request.buffer.s+
		request->first_line.u.request.method.len+1;
	t->uac[branch].uri.len=request->new_uri.len;
	t->uac[branch].br_flags = request->ruri_bflags;
	t->uac[branch].added_rr = count_local_rr( request );
	t->nr_of_outgoings++;

	/* done! */
	ret=branch;

error02:
	if(do_free_proxy) {
		free_proxy( proxy );
		pkg_free( proxy );
	}
error01:
	post_print_uac_request( request, uri, next_hop, body_clone);
	if (ret < 0) {
		/* destroy all the bavps added, the path vector and the destination,
		 * since this branch will never be properly added to
		 * the UAC list, otherwise we'll have memory leaks - razvanc */
		clean_branch(t->uac[branch]);
		memset(&t->uac[branch], 0, sizeof(t->uac[branch]));
		init_branch(&t->uac[branch], branch, t->wait_tl.set, t);
	}
error:
	return ret;
}
Exemplo n.º 23
0
Arquivo: t_fwd.c Projeto: OPSF/uClinux
/* introduce a new uac to transaction; returns its branch id (>=0)
   or error (<0); it doesn't send a message yet -- a reply to it
   might interfere with the processes of adding multiple branches
*/
int add_uac( struct cell *t, struct sip_msg *request, str *uri, str* next_hop,
             struct proxy_l *proxy, int proto )
{

    int ret;
    short temp_proxy;
    union sockaddr_union to;
    unsigned short branch;
    struct socket_info* send_sock;
    char *shbuf;
    unsigned int len;

    branch=t->nr_of_outgoings;
    if (branch==MAX_BRANCHES) {
        LOG(L_ERR, "ERROR: add_uac: maximum number of branches exceeded\n");
        ret=E_CFG;
        goto error;
    }

    /* check existing buffer -- rewriting should never occur */
    if (t->uac[branch].request.buffer) {
        LOG(L_CRIT, "ERROR: add_uac: buffer rewrite attempt\n");
        ret=ser_error=E_BUG;
        goto error;
    }

    /* check DNS resolution */
    if (proxy) {
        temp_proxy=0;
        proto=get_proto(proto, proxy->proto);
    } else {
        proxy=uri2proxy( next_hop ? next_hop : uri, proto );
        if (proxy==0)  {
            ret=E_BAD_ADDRESS;
            goto error;
        }
        proto=proxy->proto; /* uri2proxy will fix it for us */
        temp_proxy=1;
    }

    if (proxy->ok==0) {
        if (proxy->host.h_addr_list[proxy->addr_idx+1])
            proxy->addr_idx++;
        else proxy->addr_idx=0;
        proxy->ok=1;
    }

    hostent2su( &to, &proxy->host, proxy->addr_idx,
                proxy->port ? proxy->port:SIP_PORT);

    send_sock=get_send_socket( request, &to , proto);
    if (send_sock==0) {
        LOG(L_ERR, "ERROR: add_uac: can't fwd to af %d, proto %d "
            " (no corresponding listening socket)\n",
            to.s.sa_family, proto );
        ret=ser_error=E_NO_SOCKET;
        goto error01;
    }

    /* now message printing starts ... */
    shbuf=print_uac_request( t, request, branch, uri,
                             &len, send_sock, proto );
    if (!shbuf) {
        ret=ser_error=E_OUT_OF_MEM;
        goto error01;
    }

    /* things went well, move ahead and install new buffer! */
    t->uac[branch].request.dst.to=to;
    t->uac[branch].request.dst.send_sock=send_sock;
    t->uac[branch].request.dst.proto=proto;
    t->uac[branch].request.dst.proto_reserved1=0;
    t->uac[branch].request.buffer=shbuf;
    t->uac[branch].request.buffer_len=len;
    t->uac[branch].uri.s=t->uac[branch].request.buffer+
                         request->first_line.u.request.method.len+1;
    t->uac[branch].uri.len=uri->len;
    t->nr_of_outgoings++;

    /* update stats */
    proxy->tx++;
    proxy->tx_bytes+=len;

    /* done! */
    ret=branch;

error01:
    if (temp_proxy) {
        free_proxy( proxy );
        pkg_free( proxy );
    }
error:
    return ret;
}
Exemplo n.º 24
0
/*
 * Send a request using data from the dialog structure
 */
int t_uac(str* method, str* headers, str* body, dlg_t* dialog,
				transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	union sockaddr_union to_su, new_to_su;
	struct cell *new_cell;
	struct cell *backup_cell;
	struct retr_buf *request;
	static struct sip_msg *req;
	struct usr_avp **backup;
	char *buf, *buf1;
	int buf_len, buf_len1;
	int ret, flags, sflag_bk;
	int backup_route_type;
	int sip_msg_len;
	unsigned int hi;
	struct socket_info *new_send_sock;
	str h_to, h_from, h_cseq, h_callid;
	struct proxy_l *proxy, *new_proxy;
	unsigned short dst_changed;

	ret=-1;

	/*** added by dcm
	 * - needed by external ua to send a request within a dlg
	 */
	if(!dialog->hooks.next_hop && w_calculate_hooks(dialog)<0)
		goto error3;

	if(dialog->obp.s)
		dialog->hooks.next_hop = &dialog->obp;

	LM_DBG("next_hop=<%.*s>\n",dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);

	/* calculate the socket corresponding to next hop */
	proxy = uri2proxy( dialog->hooks.next_hop,
		dialog->send_sock ? dialog->send_sock->proto : PROTO_NONE );
	if (proxy==0)  {
		ret=E_BAD_ADDRESS;
		goto error3;
	}
	/* use the first address */
	hostent2su( &to_su,
		&proxy->host, proxy->addr_idx, proxy->port ? proxy->port:SIP_PORT);

	/* check/discover the send socket */
	if (dialog->send_sock) {
		/* if already set, the protocol of send sock must have the 
		   the same type as the proto required by destination URI */
		if (proxy->proto != dialog->send_sock->proto)
			dialog->send_sock = NULL;
	}
	if (dialog->send_sock==NULL) {
		/* get the send socket */
		dialog->send_sock = get_send_socket( NULL/*msg*/, &to_su, proxy->proto);
		if (!dialog->send_sock) {
			LM_ERR("no corresponding socket for af %d\n", to_su.s.sa_family);
			ser_error = E_NO_SOCKET;
			goto error2;
		}
	}
	LM_DBG("sending socket is %.*s \n",
		dialog->send_sock->name.len,dialog->send_sock->name.s);


	/* ***** Create TRANSACTION and all related  ***** */
	new_cell = build_cell( NULL/*msg*/, 1/*full UAS clone*/);
	if (!new_cell) {
		ret=E_OUT_OF_MEM;
		LM_ERR("short of cell shmem\n");
		goto error2;
	}

	/* pass the transaction flags from dialog to transaction */
	new_cell->flags |= dialog->T_flags;

	/* add the callback the transaction for LOCAL_COMPLETED event */
	flags = TMCB_LOCAL_COMPLETED;
	/* Add also TMCB_LOCAL_RESPONSE_OUT if provisional replies are desired */
	if (pass_provisional_replies || pass_provisional(new_cell))
		flags |= TMCB_LOCAL_RESPONSE_OUT;
	if(cb && insert_tmcb(&(new_cell->tmcb_hl),flags,cb,cbp,release_func)!=1){
		ret=E_OUT_OF_MEM;
		LM_ERR("short of tmcb shmem\n");
		goto error2;
	}

	if (method->len==INVITE_LEN && memcmp(method->s, INVITE, INVITE_LEN)==0)
		new_cell->flags |= T_IS_INVITE_FLAG;
	new_cell->flags |= T_IS_LOCAL_FLAG;

	request = &new_cell->uac[0].request;
	if (dialog->forced_to_su.s.sa_family == AF_UNSPEC)
		request->dst.to = to_su;
	else
		request->dst.to = dialog->forced_to_su;
	request->dst.send_sock = dialog->send_sock;
	request->dst.proto = dialog->send_sock->proto;
	request->dst.proto_reserved1 = 0;

	hi=dlg2hash(dialog);
	LOCK_HASH(hi);
	insert_into_hash_table_unsafe(new_cell, hi);
	UNLOCK_HASH(hi);

	/* copy AVPs into transaction */
	new_cell->user_avps = dialog->avps;
	dialog->avps = NULL;


	/* ***** Create the message buffer ***** */
	buf = build_uac_req(method, headers, body, dialog, 0, new_cell, &buf_len);
	if (!buf) {
		LM_ERR("failed to build message\n");
		ret=E_OUT_OF_MEM;
		goto error1;
	}

	if (local_rlist.a) {
		LM_DBG("building sip_msg from buffer\n");
		req = buf_to_sip_msg(buf, buf_len, dialog);
		if (req==NULL) {
			LM_ERR("failed to build sip_msg from buffer\n");
		} else {
			/* set this transaction as active one */
			backup_cell = get_t();
			set_t( new_cell );
			/* set transaction AVP list */
			backup = set_avp_list( &new_cell->user_avps );
			/* backup script flags */
			sflag_bk = getsflags();
			/* disable parallel forking */
			set_dset_state( 0 /*disable*/);

			/* run the route */
			swap_route_type( backup_route_type, LOCAL_ROUTE);
			run_top_route( local_rlist.a, req);
			set_route_type( backup_route_type );

			/* transfer current message context back to t */
			new_cell->uac[0].br_flags = getb0flags(req);
			/* restore the prevoius active transaction */
			set_t( backup_cell );

			set_dset_state( 1 /*enable*/);
			setsflagsval(sflag_bk);
			set_avp_list( backup );

			/* check for changes - if none, do not regenerate the buffer */
			dst_changed = 1;
			if (req->new_uri.s || req->force_send_socket!=dialog->send_sock ||
			req->dst_uri.len != dialog->hooks.next_hop->len ||
			memcmp(req->dst_uri.s,dialog->hooks.next_hop->s,req->dst_uri.len) ||
			(dst_changed=0)==0 || req->add_rm || req->body_lumps){

				new_send_sock = NULL;
				/* do we also need to change the destination? */
				if (dst_changed) {
					/* calculate the socket corresponding to next hop */
					new_proxy = uri2proxy(
						req->dst_uri.s ? &(req->dst_uri) : &req->new_uri,
						PROTO_NONE );
					if (new_proxy==0)
						goto abort_update;
					/* use the first address */
					hostent2su( &new_to_su,
						&new_proxy->host, new_proxy->addr_idx,
						new_proxy->port ? new_proxy->port:SIP_PORT);
					/* get the send socket */
					new_send_sock = get_send_socket( req, &new_to_su,
						new_proxy->proto);
					if (!new_send_sock) {
						free_proxy( new_proxy );
						pkg_free( new_proxy );
						LM_ERR("no socket found for the new destination\n");
						goto abort_update;
					}
				}

				/* if interface change, we need to re-build the via */
				if (new_send_sock && new_send_sock != dialog->send_sock) {
					LM_DBG("Interface change in local route -> "
						"rebuilding via\n");
					if (!del_lump(req,req->h_via1->name.s - req->buf,
					req->h_via1->len,0)) {
						LM_ERR("Failed to remove initial via \n");
						goto abort_update;
					}

					memcpy(req->add_to_branch_s,req->via1->branch->value.s,
						req->via1->branch->value.len);
					req->add_to_branch_len = req->via1->branch->value.len;

					/* update also info about new destination and send sock */
					dialog->send_sock = new_send_sock;
					free_proxy( proxy );
					pkg_free( proxy );
					proxy = new_proxy;
					request->dst.send_sock = new_send_sock;
					request->dst.proto = new_send_sock->proto;
					request->dst.proto_reserved1 = 0;

					/* build the shm buffer now */
					set_init_lump_flags(LUMPFLAG_BRANCH);
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						new_send_sock, new_send_sock->proto,
						MSG_TRANS_SHM_FLAG);
					reset_init_lump_flags();
					del_flaged_lumps( &req->add_rm, LUMPFLAG_BRANCH);

				} else {

					LM_DBG("Change in local route -> rebuilding buffer\n");
					/* build the shm buffer now */
					buf1 = build_req_buf_from_sip_req(req,
						(unsigned int*)&buf_len1,
						dialog->send_sock, dialog->send_sock->proto,
						MSG_TRANS_SHM_FLAG|MSG_TRANS_NOVIA_FLAG);
					/* now as it used, hide the original VIA header */
					del_lump(req,req->h_via1->name.s - req->buf,
						req->h_via1->len, 0);

				}

				if (!buf1) {
					LM_ERR("no more shm mem\n");
					/* keep original buffer */
					goto abort_update;
				}
				/* update shortcuts */
				if(!req->add_rm && !req->new_uri.s) {
					/* headers are not affected, simply tranlate */
					new_cell->from.s = new_cell->from.s - buf + buf1;
					new_cell->to.s = new_cell->to.s - buf + buf1;
					new_cell->callid.s = new_cell->callid.s - buf + buf1;
					new_cell->cseq_n.s = new_cell->cseq_n.s - buf + buf1;
				} else {
					/* use heavy artilery :D */
					if (extract_ftc_hdrs( buf1, buf_len1, &h_from, &h_to,
					&h_cseq, &h_callid)!=0 ) {
						LM_ERR("failed to update shortcut pointers\n");
						shm_free(buf1);
						goto abort_update;
					}
					new_cell->from = h_from;
					new_cell->to = h_to;
					new_cell->callid = h_callid;
					new_cell->cseq_n = h_cseq;
				}
				/* here we rely on how build_uac_req()
				   builds the first line */
				new_cell->uac[0].uri.s = buf1 +
					req->first_line.u.request.method.len + 1;
				new_cell->uac[0].uri.len = GET_RURI(req)->len;

				/* update also info about new destination and send sock */
				if (new_send_sock)
					request->dst.to = new_to_su;

				shm_free(buf);
				buf = buf1;
				buf_len = buf_len1;
				/* use new buffer */
			} else {
				/* no changes over the message, buffer is already generated,
				   just hide the original VIA for potential further branches */
				del_lump(req,req->h_via1->name.s-req->buf,req->h_via1->len,0);
			}
abort_update:
			/* save the SIP message into transaction */
			new_cell->uas.request = sip_msg_cloner( req, &sip_msg_len, 1);
			if (new_cell->uas.request==NULL) {
				/* reset any T triggering */
				new_cell->on_negative = 0;
				new_cell->on_reply = 0;
			} else {
				new_cell->uas.end_request=
					((char*)new_cell->uas.request)+sip_msg_len;
			}
			/* no parallel support in UAC transactions */
			new_cell->on_branch = 0;
			free_sip_msg(req);
		}
	}

	/* for DNS based failover, copy the DNS proxy into transaction */
	if (!disable_dns_failover) {
		new_cell->uac[0].proxy = shm_clone_proxy( proxy, 1/*do_free*/);
		if (new_cell->uac[0].proxy==NULL)
			LM_ERR("failed to store DNS info -> no DNS based failover\n");
	}

	new_cell->method.s = buf;
	new_cell->method.len = method->len;

	request->buffer.s = buf;
	request->buffer.len = buf_len;
	new_cell->nr_of_outgoings++;

	if(last_localT) {
		*last_localT = new_cell;
		REF_UNSAFE(new_cell);
	}

	if (SEND_BUFFER(request) == -1) {
		LM_ERR("attempt to send to '%.*s' failed\n",
			dialog->hooks.next_hop->len,
			dialog->hooks.next_hop->s);
	}

	if (method->len==ACK_LEN && memcmp(method->s, ACK, ACK_LEN)==0 ) {
		t_release_transaction(new_cell);
	} else {
		start_retr(request);
	}

	free_proxy( proxy );
	pkg_free( proxy );

	return 1;

error1:
	LOCK_HASH(hi);
	remove_from_hash_table_unsafe(new_cell);
	UNLOCK_HASH(hi);
	free_cell(new_cell);
error2:
	free_proxy( proxy );
	pkg_free( proxy );
error3:
	return ret;
}
Exemplo n.º 25
0
int forward_request( struct sip_msg* msg, struct proxy_l * p)
{
	union sockaddr_union to;
	unsigned int len;
	char* buf;
	struct socket_info* send_sock;
	struct socket_info* last_sock;
	str *branch;

	buf=0;

	/* calculate branch for outbound request - if the branch buffer is already
	 * set (maybe by an upper level as TM), used it; otherwise computes 
	 * the branch for stateless fwd. . According to the latest discussions
	 * on the topic, you should reuse the latest statefull branch
	 * --bogdan */
	if ( msg->add_to_branch_len==0 ) {
		branch = get_sl_branch(msg);
		if (branch==0) {
			LM_ERR("unable to compute branch\n");
			goto error;
		}
		msg->add_to_branch_len = branch->len;
		memcpy( msg->add_to_branch_s, branch->s, branch->len);
	}

	msg_callback_process(msg, REQ_PRE_FORWARD, (void *)p);

	hostent2su( &to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
	last_sock = 0;

	if (getb0flags() & tcp_no_new_conn_bflag)
		tcp_no_new_conn = 1;

	do {
		send_sock=get_send_socket( msg, &to, p->proto);
		if (send_sock==0){
			LM_ERR("cannot forward to af %d, proto %d no corresponding"
				"listening socket\n", to.s.sa_family, p->proto);
			ser_error=E_NO_SOCKET;
			continue;
		}

		if ( last_sock!=send_sock ) {

			if (buf)
				pkg_free(buf);

			buf = build_req_buf_from_sip_req(msg, &len, send_sock, p->proto, 0);
			if (!buf){
				LM_ERR("building req buf failed\n");
				tcp_no_new_conn = 0;
				goto error;
			}

			last_sock = send_sock;
		}

		if (check_blacklists( p->proto, &to, buf, len)) {
			LM_DBG("blocked by blacklists\n");
			ser_error=E_IP_BLOCKED;
			continue;
		}

		/* send it! */
		LM_DBG("sending:\n%.*s.\n", (int)len, buf);
		LM_DBG("orig. len=%d, new_len=%d, proto=%d\n",
			msg->len, len, p->proto );

		if (msg_send(send_sock, p->proto, &to, 0, buf, len)<0){
			ser_error=E_SEND;
			continue;
		}

		run_fwd_callbacks( msg, buf, len, send_sock, p->proto, &to);

		ser_error = 0;
		break;

	}while( get_next_su( p, &to, (ser_error==E_IP_BLOCKED)?0:1)==0 );

	tcp_no_new_conn = 0;

	if (ser_error) {
		update_stat( drp_reqs, 1);
		goto error;
	}

	/* sent requests stats */
	update_stat( fwd_reqs, 1);

	pkg_free(buf);
	/* received_buf & line_buf will be freed in receive_msg by free_lump_list*/
	return 0;

error:
	if (buf) pkg_free(buf);
	return -1;
}
Exemplo n.º 26
0
int update_sock_struct_from_via( union sockaddr_union* to,
								 struct sip_msg* msg,
								 struct via_body* via )
{
	struct hostent* he;
	str* name;
	int err;
	unsigned short port;
	char proto;

	port=0;
	if(via==msg->via1){ 
		/* _local_ reply, we ignore any rport or received value
		 * (but we will send back to the original port if rport is
		 *  present) */
		if ((msg->msg_flags&FL_FORCE_RPORT)||(via->rport))
			port=msg->rcv.src_port;
		else port=via->port;
		name=&(via->host); /* received=ip in 1st via is ignored (it's
							  not added by us so it's bad) */
	}else{
		/* "normal" reply, we use rport's & received value if present */
		if (via->rport && via->rport->value.s){
			DBG("update_sock_struct_from_via: using 'rport'\n");
			port=str2s(via->rport->value.s, via->rport->value.len, &err);
			if (err){
				LOG(L_NOTICE, "ERROR: update_sock_struct_from_via: bad rport value(%.*s)\n",
						via->rport->value.len, via->rport->value.s);
				port=0;
			}
		}
		if (via->received){
			DBG("update_sock_struct_from_via: using 'received'\n");
			name=&(via->received->value);
			/* making sure that we won't do SRV lookup on "received"
			 * (possible if no DNS_IP_HACK is used)*/
			if (port==0) port=via->port?via->port:SIP_PORT; 
		}else{
			DBG("update_sock_struct_from_via: using via host\n");
			name=&(via->host);
			if (port==0) port=via->port;
		}
	}
	/* we do now a malloc/memcpy because gethostbyname loves \0-terminated 
	   strings; -jiri 
	   but only if host is not null terminated
	   (host.s[len] will always be ok for a via)
	    BTW: when is via->host.s non null terminated? tm copy? - andrei 
	    Yes -- it happened on generating a 408 by TM; -jiri
	    sip_resolvehost now accepts str -janakj
	*/
	DBG("update_sock_struct_from_via: trying SRV lookup\n");
	proto=via->proto;
	he=sip_resolvehost(name, &port, &proto);
	
	if (he==0){
		LOG(L_NOTICE, "ERROR:forward_reply:resolve_host(%.*s) failure\n",
				name->len, name->s);
		return -1;
	}
		
	hostent2su(to, he, 0, port);
	return 1;
}
Exemplo n.º 27
0
static int trace_send_hep_duplicate(str *body, str *from, str *to, struct dest_info * dst2)
{
	struct dest_info dst;
	struct socket_info *si;
	struct dest_info* dst_fin = NULL;
	struct proxy_l * p=NULL /* make gcc happy */;
	void* buffer = NULL;
	union sockaddr_union from_su;
	union sockaddr_union to_su;
	unsigned int len, buflen, proto;
	struct hep_hdr hdr;
	struct hep_iphdr hep_ipheader;
	struct hep_timehdr hep_time;
	struct timeval tvb;
	struct timezone tz;

	struct hep_ip6hdr hep_ip6header;

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

	if(dup_uri_str.s==0 || dup_uri==NULL)
		return 0;


	gettimeofday( &tvb, &tz );


	/* message length */
	len = body->len 
		+ sizeof(struct hep_ip6hdr)
		+ sizeof(struct hep_hdr) + sizeof(struct hep_timehdr);;


	/* The packet is too big for us */
	if (unlikely(len>BUF_SIZE)){
		goto error;
	}

	/* Convert proto:ip:port to sockaddress union SRC IP */
	if (pipport2su(from->s, &from_su, &proto)==-1 || (pipport2su(to->s, &to_su, &proto)==-1))
		goto error;

	/* check if from and to are in the same family*/
	if(from_su.s.sa_family != to_su.s.sa_family) {
		LM_ERR("interworking detected ?\n");
		goto error;
	}

	if (!dst2){
		init_dest_info(&dst);
		/* create a temporary proxy*/
		dst.proto = PROTO_UDP;
		p=mk_proxy(&dup_uri->host, (dup_uri->port_no)?dup_uri->port_no:SIP_PORT,
				dst.proto);
		if (p==0)
		{
			LM_ERR("bad host name in uri\n");
			goto error;
		}

		hostent2su(&dst.to, &p->host, p->addr_idx, (p->port)?p->port:SIP_PORT);
		LM_DBG("setting up the socket_info\n");
		dst_fin = &dst;
	} else {
		dst_fin = dst2;
	}

	if (force_send_sock_str.s) {
		LM_DBG("force_send_sock activated, grep for the sock_info\n");
		si = grep_sock_info(&force_send_sock_uri->host,
				(force_send_sock_uri->port_no)?force_send_sock_uri->port_no:SIP_PORT,
				PROTO_UDP);
		if (!si) {
			LM_WARN("cannot grep socket info\n");
		} else {
			LM_DBG("found socket while grep: [%.*s] [%.*s]\n", si->name.len, si->name.s, si->address_str.len, si->address_str.s);
			dst_fin->send_sock = si;
		}
	}

	if (dst_fin->send_sock == 0) {
		dst_fin->send_sock=get_send_socket(0, &dst_fin->to, dst_fin->proto);
		if (dst_fin->send_sock == 0) {
			LM_ERR("can't forward to af %d, proto %d no corresponding"
					" listening socket\n", dst_fin->to.s.sa_family, dst_fin->proto);
			goto error;
		}
	}

	/* Version && proto && length */
	hdr.hp_l = sizeof(struct hep_hdr);
	hdr.hp_v = hep_version;
	hdr.hp_p = proto;

	/* AND the last */
	if (from_su.s.sa_family==AF_INET){
		/* prepare the hep headers */

		hdr.hp_f = AF_INET;
		hdr.hp_sport = htons(from_su.sin.sin_port);
		hdr.hp_dport = htons(to_su.sin.sin_port);

		hep_ipheader.hp_src = from_su.sin.sin_addr;
		hep_ipheader.hp_dst = to_su.sin.sin_addr;

		len = sizeof(struct hep_iphdr);
	}
	else if (from_su.s.sa_family==AF_INET6){
		/* prepare the hep6 headers */

		hdr.hp_f = AF_INET6;

		hdr.hp_sport = htons(from_su.sin6.sin6_port);
		hdr.hp_dport = htons(to_su.sin6.sin6_port);

		hep_ip6header.hp6_src = from_su.sin6.sin6_addr;
		hep_ip6header.hp6_dst = to_su.sin6.sin6_addr;

		len = sizeof(struct hep_ip6hdr);
	}
	else {
		LM_ERR("Unsupported protocol family\n");
		goto error;;
	}

	hdr.hp_l +=len;
	if (hep_version == 2){
		len += sizeof(struct hep_timehdr);
	}
	len += sizeof(struct hep_hdr) + body->len;
	buffer = (void *)pkg_malloc(len+1);
	if (buffer==0){
		LM_ERR("out of memory\n");
		goto error;
	}

	/* Copy job */
	memset(buffer, '\0', len+1);

	/* copy hep_hdr */
	memcpy((void*)buffer, &hdr, sizeof(struct hep_hdr));
	buflen = sizeof(struct hep_hdr);

	/* hep_ip_hdr */
	if(from_su.s.sa_family==AF_INET) {
		memcpy((void*)buffer + buflen, &hep_ipheader, sizeof(struct hep_iphdr));
		buflen += sizeof(struct hep_iphdr);
	}
	else {
		memcpy((void*)buffer+buflen, &hep_ip6header, sizeof(struct hep_ip6hdr));
		buflen += sizeof(struct hep_ip6hdr);
	}

	if(hep_version == 2) {

		hep_time.tv_sec = tvb.tv_sec;
		hep_time.tv_usec = tvb.tv_usec;
		hep_time.captid = hep_capture_id;

		memcpy((void*)buffer+buflen, &hep_time, sizeof(struct hep_timehdr));
		buflen += sizeof(struct hep_timehdr);
	}

	/* PAYLOAD */
	memcpy((void*)(buffer + buflen) , (void*)body->s, body->len);
	buflen +=body->len;

	if (msg_send_buffer(dst_fin, buffer, buflen, 1)<0)
	{
		LM_ERR("cannot send hep duplicate message\n");
		goto error;
	}

	if (p) {
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	pkg_free(buffer);
	return 0;
error:
	if(p)
	{
		free_proxy(p); /* frees only p content, not p itself */
		pkg_free(p);
	}
	if(buffer) pkg_free(buffer);
	return -1;
}