Example #1
0
File: avp.c Project: 2pac/kamailio
static int set_destination(struct sip_msg* msg, str* dest)
{
    name_addr_t nameaddr;
    
    if (!parse_nameaddr(dest, &nameaddr)) {
	return set_dst_uri(msg, &nameaddr.uri);
    } else {
	     /* it is just URI, pass it through */
	return set_dst_uri(msg, dest);
    }
}
Example #2
0
static inline struct sip_msg* buf_to_sip_msg(char *buf, unsigned int len,
															dlg_t *dialog)
{
	static struct sip_msg req;

	memset( &req, 0, sizeof(req) );
	req.id = get_next_msg_no();
	req.buf = buf;
	req.len = len;
	if (parse_msg(buf, len, &req)!=0) {
		LM_CRIT("BUG - buffer parsing failed!");
		return NULL;
	}
	/* populate some special fields in sip_msg */
	req.set_global_address=default_global_address;
	req.set_global_port=default_global_port;
	req.force_send_socket = dialog->send_sock; 
	if (set_dst_uri(&req, dialog->hooks.next_hop)) {
		LM_ERR("failed to set dst_uri");
		free_sip_msg(&req);
		return NULL;
	}
	req.rcv.proto = dialog->send_sock->proto;
	req.rcv.src_ip = req.rcv.dst_ip = dialog->send_sock->address;
	req.rcv.src_port = req.rcv.dst_port = dialog->send_sock->port_no;
	req.rcv.bind_address = dialog->send_sock;

	return &req;
}
Example #3
0
static int dst_to_msg(struct sip_msg *s_msg, struct sip_msg *d_msg)
{
	/* move RURI */
	if (set_ruri( d_msg, GET_RURI(s_msg))<0) {
		LM_ERR("failed to set new RURI\n");
		return -1;
	}

	/* move DURI (empty is accepted as reset) */
	if (set_dst_uri( d_msg, &s_msg->dst_uri)<0) {
		LM_ERR("failed to set DST URI\n");
		return -1;
	}

	/* move PATH  (empty is accepted as reset) */
	if (set_path_vector( d_msg, & s_msg->path_vec)<0) {
		LM_ERR("failed to set PATH\n");
		return -1;
	}

	/* Qval */
	set_ruri_q( d_msg, get_ruri_q(s_msg) );

	/* BFLAGS */
	setb0flags( d_msg, getb0flags(s_msg) );

	/* socket info */
	d_msg->force_send_socket = s_msg->force_send_socket;

	return 0;
}
Example #4
0
static inline int ds_update_dst(struct sip_msg *msg, str *uri,
										struct socket_info *sock, int mode)
{
	struct action act;
	switch(mode)
	{
		case 1:
			act.type = SET_HOSTPORT_T;
			act.elem[0].type = STR_ST;
			act.elem[0].u.s = *uri;
			if (uri->len>4 && strncasecmp(uri->s,"sip:",4)==0) {
				act.elem[0].u.s.s += 4;
				act.elem[0].u.s.len -= 4;
			}
			act.next = 0;
	
			if (do_action(&act, msg) < 0) {
				LM_ERR("error while setting host\n");
				return -1;
			}
			break;
		default:
			if (set_dst_uri(msg, uri) < 0) {
				LM_ERR("error while setting dst uri\n");
				return -1;
			}
		break;
	}
	if (sock)
		msg->force_send_socket = sock;
	return 0;
}
Example #5
0
static int lua_sr_setdsturi (lua_State *L)
{
	str uri;
	sr_lua_env_t *env_L;

	env_L = sr_lua_env_get();
	uri.s = (char*)lua_tostring(L, -1);
	if(uri.s==NULL)
	{
		LM_ERR("invalid uri parameter\n");
		return app_lua_return_false(L);
	}
	uri.len = strlen(uri.s);

	if(env_L->msg==NULL)
	{
		LM_WARN("invalid parameters from Lua env\n");
		return app_lua_return_false(L);
	}

	if (set_dst_uri(env_L->msg, &uri)<0)
	{
		LM_ERR("setting dst uri failed\n");
		return app_lua_return_false(L);
	}
	return app_lua_return_true(L);
}
Example #6
0
static PyObject *
msg_set_dst_uri(msgobject *self, PyObject *args)
{
    str ruri;

    if (self->msg == NULL) {
        PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
        Py_INCREF(Py_None);
        return Py_None;
    }

    if ((self->msg->first_line).type != SIP_REQUEST) {
        PyErr_SetString(PyExc_RuntimeError, "Not a request message - "
          "set destination is not possible.\n");
        Py_INCREF(Py_None);
        return Py_None;
    }

    if(!PyArg_ParseTuple(args, "s:set_dst_uri", &ruri.s))
        return NULL;

    ruri.len = strlen(ruri.s);

    if (set_dst_uri(self->msg, &ruri) < 0) {
        LM_ERR("Error in set_dst_uri\n");
        PyErr_SetString(PyExc_RuntimeError, "Error in set_dst_uri\n");
    }

    Py_INCREF(Py_None);
    return Py_None;
}
Example #7
0
static PyObject *msg_set_dst_uri(msgobject *self, PyObject *args)
{
	str ruri;

	if (self->msg == NULL) {
		PyErr_SetString(PyExc_RuntimeError, "self->msg is NULL");
		Py_INCREF(Py_None);
		return Py_None;
	}

	if ((self->msg->first_line).type != SIP_REQUEST) {
		PyErr_SetString(PyExc_RuntimeError, "Not a request message - set destination is not possible.\n");
		Py_INCREF(Py_None);
		return Py_None;
	}

	if(!PyArg_ParseTuple(args, "s:set_dst_uri", &ruri.s))
		return NULL;

	ruri.len = strlen(ruri.s);

	if (set_dst_uri(self->msg, &ruri) < 0) {
		LM_ERR("Error in set_dst_uri\n");
		PyErr_SetString(PyExc_RuntimeError, "Error in set_dst_uri\n");
	}
	/* dst_uri changes, so it makes sense to re-use the current uri for
	 * forking */
	ruri_mark_new(); /* re-use uri for serial forking */

	Py_INCREF(Py_None);
	return Py_None;
}
Example #8
0
/*! \brief
 * Lookup contact in the database and rewrite Request-URI
 * \return:  1 : contacts found and returned
 *          -1 : not found
 *          -2 : error
 */
int lookup_transport(struct sip_msg* _m, udomain_t* _d, str* _uri) {
    str uri;
    pcontact_t* pcontact;
    char tmp[MAX_URI_SIZE];
    char srcip[20];
    str received_host;
    str tmp_s;
    int ret = 1;

    if (_m->new_uri.s) uri = _m->new_uri;
    else uri = _m->first_line.u.request.uri;

    received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
    received_host.s = srcip;
    
    //now lookup in usrloc
    ul.lock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
    if (ul.get_pcontact(_d, &uri, &received_host, _m->rcv.src_port, &pcontact) != 0) { //need to insert new contact
	LM_WARN("received request for contact that we don't know about\n");
	ret = -1;
	goto done;
    }
    
    if (pcontact->received_proto != _m->rcv.proto) {
	reset_dst_uri(_m);
	memset(tmp, 0, MAX_URI_SIZE);	
	switch (pcontact->received_proto) {
	    case PROTO_TCP:
		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=tcp", pcontact->aor.len, pcontact->aor.s);
		break;
	    case PROTO_UDP:
		snprintf(tmp, MAX_URI_SIZE, "%.*s;transport=udp", pcontact->aor.len, pcontact->aor.s);
		break;
	    default:
		LM_WARN("unsupported transport [%d]\n", pcontact->received_proto);
		ret = -2;
		goto done;
	}

	tmp_s.s = tmp;
	tmp_s.len = strlen(tmp);
	if (set_dst_uri(_m, &tmp_s) < 0) {
	    LM_ERR("failed to set dst_uri for terminating UE\n");
	    ret = -2;
	    goto done;
	}	
	LM_DBG("Changed dst URI transport for UE to [%.*s]\n", tmp_s.len, tmp_s.s);
    }
	
done:
    ul.unlock_udomain(_d, &uri, &received_host, _m->rcv.src_port);
    return ret;
}
Example #9
0
int w_setdsturi(struct sip_msg *msg, char *uri, str *s2)
{
	str s;

	/* todo: fixup */
	s.s = uri;
	s.len = strlen(uri);

	if(set_dst_uri(msg, &s)!=0)
		return -1;
	/* dst_uri changes, so it makes sense to re-use the current uri for
		forking */
	ruri_mark_new(); /* re-use uri for serial forking */
	return 1;

}
Example #10
0
int t_replicate(struct sip_msg *p_msg, str *dst, int flags)
{
	/* this is a quite horrible hack -- we just take the message
	   as is, including Route-s, Record-route-s, and Vias ,
	   forward it downstream and prevent replies received
	   from relaying by setting the replication/local_trans bit;

		nevertheless, it should be good enough for the primary
		customer of this function, REGISTER replication

		if we want later to make it thoroughly, we need to
		introduce delete lumps for all the header fields above
	*/
	struct cell *t;

	if ( set_dst_uri( p_msg, dst)!=0 ) {
		LM_ERR("failed to set dst uri\n");
		return -1;
	}

	if ( branch_uri2dset( GET_RURI(p_msg) )!=0 ) {
		LM_ERR("failed to convert uri to dst\n");
		return -1;
	}

	t=get_t();

	if (!t || t==T_UNDEFINED) {
		/* no transaction yet */
		if (route_type==FAILURE_ROUTE) {
			LM_CRIT("BUG - undefined transaction in failure route\n");
			return -1;
		}
		return t_relay_to( p_msg, NULL, flags|TM_T_RELAY_repl_FLAG);
	} else {
		/* transaction already created */
		if (p_msg->REQ_METHOD==METHOD_ACK)
			/* local ACK */
			return -1;

		t->flags|=T_IS_LOCAL_FLAG;

		return t_forward_nonack( t, p_msg, NULL, 1/*reset*/, 0/*unlocked*/);
	}
}
Example #11
0
int lookup_path_to_contact(struct sip_msg* _m, char* contact_uri) {
    ucontact_t* contact;
    str s_contact_uri;
    str path_dst;

    get_act_time();
    if (get_str_fparam(&s_contact_uri, _m, (fparam_t*) contact_uri) < 0) {
        LM_ERR("failed to get RURI\n");
        return -1;
    }
    LM_DBG("Looking up contact [%.*s]\n", s_contact_uri.len, s_contact_uri.s);

    if (ul.get_ucontact(NULL, &s_contact_uri, 0, 0, 0, &contact) == 0) { //get_contact returns with lock

        if (!VALID_CONTACT(contact, act_time)) {
            LM_DBG("Contact is not valid...ignoring\n");
            ul.release_ucontact(contact);
        } else {
            LM_DBG("CONTACT FOUND and path is [%.*s]\n", contact->path.len, contact->path.s);

            if (get_path_dst_uri(&contact->path, &path_dst) < 0) {
                LM_ERR("failed to get dst_uri for Path\n");
                ul.release_ucontact(contact);
                return -1;
            }
            if (set_path_vector(_m, &contact->path) < 0) {
                LM_ERR("failed to set path vector\n");
                ul.release_ucontact(contact);
                return -1;
            }
            if (set_dst_uri(_m, &path_dst) < 0) {
                LM_ERR("failed to set dst_uri of Path\n");
                ul.release_ucontact(contact);
                return -1;
            }

            ul.release_ucontact(contact);
            return 1;
        }
    }
    LM_DBG("no contact found for [%.*s]\n", s_contact_uri.len, s_contact_uri.s);
    return -1;
}
Example #12
0
/*! \brief
 * rr callback
 */
void path_rr_callback(struct sip_msg *_m, str *r_param, void *cb_param)
{
	param_hooks_t hooks;
	param_t *params;
			
	if (parse_params(r_param, CLASS_CONTACT, &hooks, &params) != 0) {
		LM_ERR("failed to parse route parameters\n");
		return;
	}

	if (hooks.contact.received) {
		if (set_dst_uri(_m, &hooks.contact.received->body) != 0) {
			LM_ERR("failed to set dst-uri\n");
			free_params(params);
			return;
		}
		/* dst_uri changed, so it makes sense to re-use the current uri for
			forking */
		ruri_mark_new(); /* re-use uri for serial forking */
	}
	free_params(params);
}
Example #13
0
/*! \brief
 * Lookup contact in the database and rewrite Request-URI
 * \return: -1 : not found
 *          -2 : found but method not allowed
 *          -3 : error
 */
int lookup(struct sip_msg* _m, udomain_t* _d) {
    impurecord_t* r;
    str aor, uri;
    ucontact_t* ptr;
    int res;
    int ret;
    str path_dst;
    flag_t old_bflags;
    int i = 0;


    if (_m->new_uri.s) uri = _m->new_uri;
    else uri = _m->first_line.u.request.uri;

    if (extract_aor(&uri, &aor) < 0) {
	LM_ERR("failed to extract address of record\n");
	return -3;
    }

    get_act_time();

    ul.lock_udomain(_d, &aor);
    res = ul.get_impurecord(_d, &aor, &r);
    if (res > 0) {
	LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
	ul.unlock_udomain(_d, &aor);
	return -1;
    }
    ret = -1;

    while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) {
	if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) {
	    LM_DBG("Found a valid contact [%.*s]\n", ptr->c.len, ptr->c.s);
	    i++;
	    break;
	}
	i++;
    }

    /* look first for an un-expired and suported contact */
    if (ptr == 0) {
	/* nothing found */
	goto done;
    }

    ret = 1;
    if (ptr) {
	if (rewrite_uri(_m, &ptr->c) < 0) {
	    LM_ERR("unable to rewrite Request-URI\n");
	    ret = -3;
	    goto done;
	}

	/* reset next hop address */
	reset_dst_uri(_m);

	/* If a Path is present, use first path-uri in favour of
	 * received-uri because in that case the last hop towards the uac
	 * has to handle NAT. - agranig */
	if (ptr->path.s && ptr->path.len) {
	    if (get_path_dst_uri(&ptr->path, &path_dst) < 0) {
		LM_ERR("failed to get dst_uri for Path\n");
		ret = -3;
		goto done;
	    }
	    if (set_path_vector(_m, &ptr->path) < 0) {
		LM_ERR("failed to set path vector\n");
		ret = -3;
		goto done;
	    }
	    if (set_dst_uri(_m, &path_dst) < 0) {
		LM_ERR("failed to set dst_uri of Path\n");
		ret = -3;
		goto done;
	    }
	} else if (ptr->received.s && ptr->received.len) {
	    if (set_dst_uri(_m, &ptr->received) < 0) {
		ret = -3;
		goto done;
	    }
	}

	set_ruri_q(ptr->q);

	old_bflags = 0;
	getbflagsval(0, &old_bflags);
	setbflagsval(0, old_bflags | ptr->cflags);

	if (ptr->sock)
	    set_force_socket(_m, ptr->sock);

	ptr = ptr->next;
    }

    /* Append branches if enabled */
    if (!cfg_get(registrar, registrar_cfg, append_branches)) goto done;

    //the last i was the first valid contact we found - let's go through the rest of valid contacts and append the branches.
    while (i < MAX_CONTACTS_PER_IMPU && (ptr = r->newcontacts[i])) {
	if (VALID_CONTACT(ptr, act_time) && allowed_method(_m, ptr)) {
	    path_dst.len = 0;
	    if (ptr->path.s && ptr->path.len
		    && get_path_dst_uri(&ptr->path, &path_dst) < 0) {
		LM_ERR("failed to get dst_uri for Path\n");
		continue;
	    }

	    /* The same as for the first contact applies for branches
	     * regarding path vs. received. */
	    if (km_append_branch(_m, &ptr->c, path_dst.len ? &path_dst : &ptr->received,
		    &ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) {
		LM_ERR("failed to append a branch\n");
		/* Also give a chance to the next branches*/
		continue;
	    }
	}
	i++;
    }

done:
    ul.unlock_udomain(_d, &aor);
    return ret;
}
Example #14
0
/**
 * Force Service routes (upon request)
 */
int force_service_routes(struct sip_msg* _m, udomain_t* _d) {
	struct hdr_field *it;
	int i;
	str new_route_header;
	struct lump* lmp = NULL;
	char * buf;
	pcontact_t * c = getContactP(_m, _d, PCONTACT_REGISTERED,0 ,0);
//	char srcip[20];
//	str received_host;
        struct via_body* vb;
        unsigned short port;
        unsigned short proto;
	
	// Contact not found => not following service-routes
	if (c == NULL) return -1;

	/* we need to be sure we have seen all HFs */
	parse_headers(_m, HDR_EOH_F, 0);

        vb = cscf_get_ue_via(_m);
        port = vb->port?vb->port:5060;
        proto = vb->proto;
        
	/* Save current buffer */
	buf = _m->buf;

	// Delete old Route headers:
	if (_m->route) {
		for (it = _m->route; it; it = it->next) {
			if (it->type == HDR_ROUTE_T) {
				if ((lmp = del_lump(_m, it->name.s - buf, it->len, HDR_ROUTE_T)) == 0) {
					LM_ERR("del_lump failed \n");
					return -1;
				}
			}
		}
	}

	/* Reset dst_uri if previously set either by loose route or manually */
	if (_m->dst_uri.s && _m->dst_uri.len) {
		pkg_free(_m->dst_uri.s);
		_m->dst_uri.s = NULL;
		_m->dst_uri.len = 0;
	}
	
//	received_host.len = ip_addr2sbuf(&_m->rcv.src_ip, srcip, sizeof(srcip));
//	received_host.s = srcip;

	/* Lock this record while working with the data: */
	ul.lock_udomain(_d, &vb->host, port, proto);

	if (c->num_service_routes > 0) {
		/* Create anchor for new Route-Header: */
		lmp = anchor_lump(_m, _m->headers->name.s - buf,0,0);
		if (lmp == 0) {
			LM_ERR("Failed to get anchor lump\n");
			goto error;
		}	
		/* Calculate the length: */
		new_route_header.len = route_start.len +
			route_end.len + (c->num_service_routes-1) * route_sep.len;

		for(i=0; i< c->num_service_routes; i++)
			new_route_header.len+=c->service_routes[i].len;		
		/* Allocate the memory for this new header: */
		new_route_header.s = pkg_malloc(new_route_header.len);
		if (!new_route_header.s) {
			LM_ERR("Error allocating %d bytes\n", new_route_header.len);
			goto error;
		}
		
		/* Construct new header */
		new_route_header.len = 0;
		STR_APPEND(new_route_header, route_start);
		for(i=0; i < c->num_service_routes; i++) {
			if (i) STR_APPEND(new_route_header, route_sep);
			STR_APPEND(new_route_header, c->service_routes[i]);
		}
		STR_APPEND(new_route_header, route_end);

		LM_DBG("Setting route header to <%.*s> \n", new_route_header.len, new_route_header.s);

		if ((lmp = insert_new_lump_after(lmp, new_route_header.s, new_route_header.len, HDR_ROUTE_T)) == 0) {
			LM_ERR("Error inserting new route set\n");
			pkg_free(new_route_header.s);
			goto error;
		}

		LM_DBG("Setting dst_uri to <%.*s> \n", c->service_routes[0].len,
			c->service_routes[0].s);

		if (set_dst_uri(_m, &c->service_routes[0]) !=0 ) {
			LM_ERR("Error setting new dst uri\n");
			goto error;
		}
	}
	/* Unlock domain */
	ul.unlock_udomain(_d, &vb->host, port, proto);
	return 1;
error:
	/* Unlock domain */
	ul.unlock_udomain(_d, &vb->host, port, proto);
	return -1;
	
    return 1;
}
Example #15
0
/*
 * Lookup contact in the database and rewrite Request-URI
 */
int lookup(struct sip_msg* _m, char* _t, char* _s)
{
	urecord_t* r;
	str uid;
	ucontact_t* ptr;
	int res;
	unsigned int nat;
	str new_uri; 	

	nat = 0;
	
	if (get_to_uid(&uid, _m) < 0) return -1;

	get_act_time();

	ul.lock_udomain((udomain_t*)_t);
	res = ul.get_urecord((udomain_t*)_t, &uid, &r);
	if (res < 0) {
		LOG(L_ERR, "lookup(): Error while querying usrloc\n");
		ul.unlock_udomain((udomain_t*)_t);
		return -2;
	}
	
	if (res > 0) {
		DBG("lookup(): '%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s));
		ul.unlock_udomain((udomain_t*)_t);
		return -3;
	}

	ptr = r->contacts;
	while ((ptr) && !VALID_CONTACT(ptr, act_time))
		ptr = ptr->next;
	
	if (ptr) {
		if (ptr->received.s && ptr->received.len) {
			if (received_to_uri){
				if (add_received(&new_uri, &ptr->c, &ptr->received)<0){
					LOG(L_ERR, "ERROR: lookup(): out of memory\n");
					return -4;
				}
			/* replace the msg uri */
			if (_m->new_uri.s)      pkg_free(_m->new_uri.s);
			_m->new_uri=new_uri;
			_m->parsed_uri_ok=0;
			ruri_mark_new();
			goto skip_rewrite_uri;
			}else if (set_dst_uri(_m, &ptr->received) < 0) {
				ul.unlock_udomain((udomain_t*)_t);
				return -4;
			}
		}
		
		if (rewrite_uri(_m, &ptr->c) < 0) {
			LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n");
			ul.unlock_udomain((udomain_t*)_t);
			return -4;
		}

		if (ptr->sock) {
			set_force_socket(_m, ptr->sock);
		}

skip_rewrite_uri:

		set_ruri_q(ptr->q);

		nat |= ptr->flags & FL_NAT;
		ptr = ptr->next;
	} else {
		     /* All contacts expired */
		ul.unlock_udomain((udomain_t*)_t);
		return -5;
	}
	
	     /* Append branches if enabled */
	if (!append_branches) goto skip;

	while(ptr) {
		if (VALID_CONTACT(ptr, act_time)) {
			if (received_to_uri && ptr->received.s && ptr->received.len){
				if (add_received(&new_uri, &ptr->c, &ptr->received)<0){
					LOG(L_ERR, "ERROR: lookup(): branch: out of memory\n");
					goto cont; /* try to continue */
				}
				if (append_branch(_m, &new_uri, 0, 0, ptr->q, 0, 0) == -1) {
					LOG(L_ERR, "lookup(): Error while appending a branch\n");
					pkg_free(new_uri.s);
					if (ser_error==E_TOO_MANY_BRANCHES) goto skip;
					else goto cont; /* try to continue, maybe we have an
							                   oversized contact */
				}
				pkg_free(new_uri.s); /* append_branch doesn't free it */
			}else{
				if (append_branch(_m, &ptr->c, &ptr->received, 0 /* path */,
									ptr->q, 0 /* brflags*/, ptr->sock) == -1) {
					LOG(L_ERR, "lookup(): Error while appending a branch\n");
					goto skip; /* Return OK here so the function succeeds */
				}
			}
			
			nat |= ptr->flags & FL_NAT; 
		} 
cont:
		ptr = ptr->next; 
	}
	
 skip:
	ul.unlock_udomain((udomain_t*)_t);
	if (nat) setflag(_m, load_nat_flag);
	return 1;
}
Example #16
0
int uac_reg_request_to(struct sip_msg *msg, str *src, unsigned int mode)
{
	char ruri[MAX_URI_SIZE];
	struct sip_uri puri;
	reg_uac_t *reg = NULL;
	pv_value_t val;
	struct action act;
	struct run_act_ctx ra_ctx;

	switch(mode)
	{
		case 0:
			reg = reg_ht_get_byuuid(src);
			break;
		case 1:
			if(reg_use_domain)
			{
				if (parse_uri(src->s, src->len, &puri)!=0)
				{
					LM_ERR("failed to parse uri\n");
					return -2;
				}
				reg = reg_ht_get_byuser(&puri.user, &puri.host);
			} else {
				reg = reg_ht_get_byuser(src, NULL);
			}
			break;
		default:
			LM_ERR("unknown mode: %d\n", mode);
			return -1;
	}

	if(reg==NULL)
	{
		LM_DBG("no user: %.*s\n", src->len, src->s);
		return -1;
	}

	// Set uri ($ru)
	snprintf(ruri, MAX_URI_SIZE, "sip:%.*s@%.*s",
		reg->r_username.len, reg->r_username.s,
		reg->r_domain.len, reg->r_domain.s);
	memset(&act, 0, sizeof(act));
	act.type = SET_URI_T;
	act.val[0].type = STRING_ST;
	act.val[0].u.string = ruri;
	init_run_actions_ctx(&ra_ctx);
	if (do_action(&ra_ctx, &act, msg) < 0) {
		LM_ERR("error while setting request uri\n");
		return -1;
	}

	// Set auth_proxy ($du)
	if (set_dst_uri(msg, &reg->auth_proxy) < 0) {
		LM_ERR("error while setting outbound proxy\n");
		return -1;
	}

	memset(&val, 0, sizeof(pv_value_t));
	val.flags |= PV_VAL_STR;

	// Set auth_realm
	val.rs = reg->realm;
	if(pv_set_spec_value(msg, &auth_realm_spec, 0, &val)!=0) {
		LM_ERR("error while setting auth_realm\n");
		return -1;
	}

	// Set auth_username
	val.rs = reg->auth_username;
	if(pv_set_spec_value(msg, &auth_username_spec, 0, &val)!=0) {
		LM_ERR("error while setting auth_username\n");
		return -1;
	}

	// Set auth_password
	val.rs = reg->auth_password;
	if(pv_set_spec_value(msg, &auth_password_spec, 0, &val)!=0) {
		LM_ERR("error while setting auth_password\n");
		return -1;
	}

	return 1;
}
Example #17
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;
}
Example #18
0
int lb_route(struct sip_msg *req, int group, struct lb_res_str_list *rl,
						unsigned int flags, struct lb_data *data, int reuse)
{
	/* resources for previous iteration */
	static struct lb_resource **res_prev = NULL;
	static unsigned int res_prev_size = 0;
	/* resources for new iteration */
	static struct lb_resource **res_new = NULL;
	static unsigned int res_new_size = 0;
	/* probed destinations bitmap */
	static unsigned int *dst_bitmap = NULL;
	static unsigned int bitmap_size = 0;
	/* selected destinations buffer */
	static struct lb_dst **dsts = NULL;
	static unsigned int dsts_size = 0;

	/* control vars */
	struct lb_resource **res_cur;
	int res_prev_n, res_new_n, res_cur_n;
	struct lb_dst **dsts_cur;
	struct lb_dst *last_dst, *dst;
	unsigned int dsts_size_cur, dsts_size_max;
	unsigned int *dst_bitmap_cur;
	unsigned int bitmap_size_cur;
	struct dlg_cell *dlg;

	/* AVP related vars */
	struct usr_avp *group_avp;
	struct usr_avp *flags_avp;
	struct usr_avp *mask_avp;
	struct usr_avp *id_avp;
	struct usr_avp *res_avp;
	int_str group_val;
	int_str flags_val;
	int_str mask_val;
	int_str id_val;
	int_str res_val;

	/* iterators, e.t.c. */
	struct lb_dst *it_d;
	struct lb_resource *it_r;
	int load, it_l;
	int i, j, cond;


	/* init control vars state */
	res_cur = NULL;
	res_cur_n = res_prev_n = res_new_n = 0;
	last_dst = dst = NULL;
	dst_bitmap_cur = NULL;

	/* search and fill new resources references if we should not reuse
	   previous iteration data */
	if( !reuse ) {
		res_new_n = rl->n;
		/* adjust size of statically allocated buffer */
		if( res_new_n > res_new_size ) {
			res_new = (struct lb_resource **)pkg_realloc
				(res_new, (res_new_n * sizeof(struct lb_resource *)));
			if( res_new == NULL ) {
				res_new_size = 0;
				LM_ERR("no more pkg mem - resources ptr buffer realloc "
					"failure\n");
				return -1;
			}
			res_new_size = res_new_n;
		}
		/* fill resource references */
		for( it_r=data->resources,i=0 ; it_r ; it_r=it_r->next ) {
			if( search_resource_str(rl, &it_r->name) ) {
				res_new[i++] = it_r;
				LM_DBG("initial call of LB - found requested %d/%d "
					"resource [%.*s]\n", i, res_new_n,
					it_r->name.len, it_r->name.s);
			}
		}
		if( i != res_new_n ) {
			LM_ERR("initial call of LB - unknown resource found in "
				"input string\n");
			return -1;
		}

		/* set 'res_new' as current iteration buffer */
		res_cur = res_new;
		res_cur_n = res_new_n;
	}

	/* always search for previous iteration data,
	   no matter if we will reuse it or not */
	group_avp = search_first_avp(0, group_avp_name, &group_val, NULL);
	flags_avp = search_first_avp(0, flags_avp_name, &flags_val, NULL);
	mask_avp  = search_first_avp(0, mask_avp_name,  &mask_val,  NULL);
	id_avp    = search_first_avp(0, id_avp_name,    &id_val,    NULL);
	/* sanity checks for fetched AVPs */
	if( group_avp && !(is_avp_str_val(group_avp) == 0) )
		{ destroy_avp(group_avp); group_avp = NULL; }
	if( flags_avp && !(is_avp_str_val(flags_avp) == 0) )
		{ destroy_avp(flags_avp); flags_avp = NULL; }
	if( mask_avp  && !(is_avp_str_val(mask_avp)  != 0) )
		{ destroy_avp(mask_avp);  mask_avp  = NULL; }
	if( id_avp    && !(is_avp_str_val(id_avp)    == 0) )
		{ destroy_avp(id_avp);    id_avp    = NULL; }

	/* get previous iteration destination, if any */
	if( id_avp ) {
		for( it_d=data->dsts ; it_d ; it_d=it_d->next ) {
			if( it_d->id == id_val.n ) {
				last_dst = it_d;
				LM_DBG("%s call of LB - found previous dst %d [%.*s]\n",
					(reuse ? "sequential" : "initial"), last_dst->id,
					last_dst->profile_id.len, last_dst->profile_id.s);
				break;
			}
		}
	}
	/* search and fill previous iteration resources references only if... */
	if(
		/* we should reuse previous resources list */
		reuse ||
		/* we have 'last_dst', i.e. previous iteration was successfull and
		 * we need to clean it up */
		(last_dst != NULL)
	) {
		do {
			cond = 0; /* use it here as a 'start loop again' flag */
			res_prev_n = 0;
			res_avp = search_first_avp(0, res_avp_name, &res_val, NULL);
			for( ; res_avp ; res_avp=search_next_avp(res_avp, &res_val) ) {
				/* ignore AVPs with invalid type */
				if( !(is_avp_str_val(res_avp) != 0) ) continue;

				if ( (it_r=get_resource_by_name( data, &res_val.s))==NULL ) {
					LM_WARN("%s call of LB - ignore unknown previous "
						"resource [%.*s]\n", (reuse?"sequential":"initial"),
						res_val.s.len, res_val.s.s);
					continue;
				}
				/* fill buffer only if buffer size not exeeded */
				if( res_prev_n < res_prev_size ) {
					res_prev[res_prev_n] = it_r;
					LM_DBG("%s call of LB - found previous resource [%.*s]\n",
						(reuse ? "sequential" : "initial"),
						it_r->name.len, it_r->name.s);
				}
				res_prev_n++;
			}
			/* adjust size of statically allocated buffer */
			if( res_prev_n > res_prev_size ) {
				/* small hack: if we need to adjust 'res_prev' buffer adjust
				 * it according to 'res_new' size to minimize 
				 * future pkg_realloc()'s */
				if( !reuse && (res_prev_n < res_new_n) )
					res_prev_n = res_new_n;

				res_prev = (struct lb_resource **)pkg_realloc
					(res_prev, (res_prev_n * sizeof(struct lb_resource *)));
				if( res_prev == NULL ) {
					res_prev_size = 0;
					LM_ERR("no more pkg mem - previous resources ptr "
						"buffer realloc failure\n");
					return -1;
				}
				res_prev_size = res_prev_n;
				cond = 1;
			}
		}
		while( cond );
	}

	/* reuse previous iteration resources, group and flags */
	if( reuse ) {
		/* set 'res_prev' as current iteration buffer */
		res_cur = res_prev;
		res_cur_n = res_prev_n;
		if( res_cur_n == 0 ) {
			LM_ERR("sequential call of LB - cannot find previous resources\n");
			return -1;
		}
		if( group_avp )
			group = group_val.n;
		else {
			LM_ERR("sequential call of LB - cannot find previous group\n");
			return -1;
		}
		if( flags_avp )
			flags = flags_val.n;
		else
			flags = LB_FLAGS_DEFAULT;

		LM_DBG("sequential call of LB - found previous group %d and "
			"flags 0x%x\n", group, flags);
	}

	/* sanity check - double check that we have a resource list to work with */
	if( (res_cur == NULL) || (res_cur_n == 0) ) {
		LM_ERR("%s call of LB - no resources list to work with\n",
			(reuse ? "sequential" : "initial"));
		return -1;
	}


	/* [re-]initialize/reuse destinations mask */

	/* sanity check - always calculate current iteration
	 * res_cur[]->bitmap_size */
	bitmap_size_cur=(unsigned int)(-1);
	for( i=0 ; i<res_cur_n ; i++ ) {
		if( bitmap_size_cur > res_cur[i]->bitmap_size )
			bitmap_size_cur = res_cur[i]->bitmap_size;
	}
	/* always try to reuse 'mask' buffer from AVP, even if we need 
	 * to reinitialize it to avoid un-neded AVP ops */
	if(mask_avp && (mask_val.s.len==(bitmap_size_cur*sizeof(unsigned int)))) {
		dst_bitmap_cur = (unsigned int *)mask_val.s.s;
	}
	/* ...or use our static buffer */
	if( dst_bitmap_cur == NULL ) {
		/* adjust size of statically allocated buffer */
		if( bitmap_size_cur > bitmap_size ) {
			dst_bitmap = (unsigned int *)pkg_realloc
				(dst_bitmap, (bitmap_size_cur * sizeof(unsigned int)));
			if( dst_bitmap == NULL ) {
				bitmap_size = 0;
				LM_ERR("no more pkg mem - dst bitmap buffer realloc failed\n");
				return -1;
			}
			bitmap_size = bitmap_size_cur;
		}
		dst_bitmap_cur = dst_bitmap;
	}
	/* reinitalize buffer if... */
	if(
		(dst_bitmap_cur == dst_bitmap) || /* it is our static buffer */
		!reuse /* should not reuse previous iteration data */
	) {
		if( reuse ) {
			LM_WARN("sequential call of LB - cannot %s previous mask, routing "
				"will be re-started", (mask_avp ? "reuse" : "find"));
		}

		memset(dst_bitmap_cur, 0xff, (bitmap_size_cur * sizeof(unsigned int)));
		for( i=0 ; i<res_cur_n ; i++ ) {
			for( j=0 ; j<bitmap_size_cur ; j++ )
				dst_bitmap_cur[j] &= res_cur[i]->dst_bitmap[j];
		}
	}

	/* init selected destinations buff */
	dsts_cur = NULL;
	dsts_size_max = (flags & LB_FLAGS_RANDOM) ? data->dst_no : 1;
	if( dsts_size_max > 1 ) {
		if( dsts_size_max > dsts_size ) {
			dsts = (struct lb_dst **)pkg_realloc
				(dsts, (dsts_size_max * sizeof(struct lb_dst *)));
			if( dsts == NULL ) {
				dsts_size_max = dsts_size = 0;
				LM_WARN("no more pkg mem - dsts buffer realloc failed\n");
			}
			else
				dsts_size = dsts_size_max;
		}
		dsts_cur = dsts;
	}
	if( dsts_cur == NULL ) {
		/* fallback to no-buffer / 'select first' scenario */
		dsts_cur = &dst;
		dsts_size_max = 1;
	}

	/* be sure the dialog is created */
	if ( (dlg=lb_dlg_binds.get_dlg())==NULL ) {
		if( lb_dlg_binds.create_dlg(req, 0) != 1 ) {
			LM_ERR("%s call of LB - failed to create dialog\n",
				(reuse ? "sequential" : "initial"));
			return -1;
		}
		/* get the dialog reference */
		dlg = lb_dlg_binds.get_dlg();
	}

	/* we're initialized from here and no errors could abort us */

	/* remove the dialog from previous profiles, if any */
	if ( (last_dst != NULL) && (res_prev_n > 0) ) {
		for( i=0 ; i<res_prev_n ; i++ ) {
			if( lb_dlg_binds.unset_profile(dlg, &last_dst->profile_id,
			res_prev[i]->profile) != 1 )
				LM_ERR("%s call of LB - failed to remove from profile [%.*s]"
					"->[%.*s]\n", (reuse ? "sequential" : "initial"),
					res_prev[i]->profile->name.len,
					res_prev[i]->profile->name.s, last_dst->profile_id.len,
					last_dst->profile_id.s );
		}
	}


	/* lock resources */
	for( i=0 ; i<res_cur_n ; i++ )
		lock_get(res_cur[i]->lock);

	/* do the load-balancing */

	/*  select destinations */
	cond = 0; /* use it here as a 'first iteration' flag */
	load = it_l = 0;
	dsts_size_cur = 0;
	for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) {
		if( it_d->group == group ) {
			if( (dst_bitmap_cur[i] & (1 << j)) &&
			((it_d->flags & LB_DST_STAT_DSBL_FLAG) == 0) ) {
				/* valid destination (group & resources & status) */
				if( get_dst_load(res_cur, res_cur_n, it_d, flags, &it_l) ) {
					/* only valid load here */
					if( (it_l > 0) || (flags & LB_FLAGS_NEGATIVE) ) {
						/* only allowed load here */
						if( !cond/*first pass*/ || (it_l > load)/*new max*/ ) {
							cond = 1;
							/* restart buffer */
							dsts_size_cur = 0;
						} else if( it_l < load ) {
							/* lower availability -> new iteration */
							continue;
						}

						/* add destination to to selected destinations buffer,
						 * if we have a room for it */
						if( dsts_size_cur < dsts_size_max ) {
							load = it_l;
							dsts_cur[dsts_size_cur++] = it_d;

							LM_DBG("%s call of LB - destination %d <%.*s> "
								"selected for LB set with free=%d\n",
								(reuse ? "sequential" : "initial"),
								it_d->id, it_d->uri.len, it_d->uri.s, it_l
							);
						}
					}
				} else {
					LM_WARN("%s call of LB - skipping destination %d <%.*s> - "
						"unable to calculate free resources\n",
						(reuse ? "sequential" : "initial"),
						it_d->id, it_d->uri.len, it_d->uri.s
					);
				}
			}
			else {
				LM_DBG("%s call of LB - skipping destination %d <%.*s> "
					"(filtered=%d , disabled=%d)\n",
					(reuse ? "sequential" : "initial"),
					it_d->id, it_d->uri.len, it_d->uri.s,
					((dst_bitmap_cur[i] & (1 << j)) ? 0 : 1),
					((it_d->flags & LB_DST_STAT_DSBL_FLAG) ? 1 : 0)
				);
			}
		}
		if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; }
	}
	/* choose one destination among selected */
	if( dsts_size_cur > 0 ) {
		if( (dsts_size_cur > 1) && (flags & LB_FLAGS_RANDOM) ) {
			dst = dsts_cur[rand() % dsts_size_cur];
		} else {
			dst = dsts_cur[0];
		}
	}


	if( dst != NULL ) {
		LM_DBG("%s call of LB - winning destination %d <%.*s> selected "
			"for LB set with free=%d\n",
			(reuse ? "sequential" : "initial"),
			dst->id, dst->uri.len, dst->uri.s, load );

		/* add to the profiles */
		for( i=0 ; i<res_cur_n ; i++ ) {
			if( lb_dlg_binds.set_profile(dlg, &dst->profile_id,
			res_cur[i]->profile, 0) != 0 )
				LM_ERR("%s call of LB - failed to add to profile [%.*s]->"
					"[%.*s]\n", (reuse ? "sequential" : "initial"),
					res_cur[i]->profile->name.len, res_cur[i]->profile->name.s,
					dst->profile_id.len, dst->profile_id.s);
		}

		/* set dst as used (not selected) */
		for( it_d=data->dsts,i=0,j=0 ; it_d ; it_d=it_d->next ) {
			if( it_d == dst ) { dst_bitmap_cur[i] &= ~(1 << j); break; }
			if( ++j == (8 * sizeof(unsigned int)) ) { i++; j=0; }
		}
	} else {
		LM_DBG("%s call of LB - no destination found\n",
			(reuse ? "sequential" : "initial"));
	}

	/* unlock resources */
	for( i=0 ; i<res_cur_n ; i++ )
		lock_release(res_cur[i]->lock);

	/* we're done with load-balancing, now save state */

	/* save state - group */
	if( group_avp == NULL ) {
		group_val.n = group;
		if( add_avp(0, group_avp_name, group_val) != 0 ) {
			LM_ERR("failed to add GROUP AVP\n");
		}
	} else if( group_val.n != group ) {
		group_avp->data = (void *)(long)group;
	}
	/* save state - flags, save only if they are set */
	if( flags_avp == NULL ) {
		if( flags != LB_FLAGS_DEFAULT ) {
			flags_val.n = flags;
			if( add_avp(0, flags_avp_name, flags_val) != 0 ) {
				LM_ERR("failed to add FLAGS AVP\n");
			}
		}
	} else if( flags_val.n != flags ) {
		flags_avp->data = (void *)(long)flags;
	}
	/* save state - dst_bitmap mask */
	if( (mask_avp!=NULL) && (dst_bitmap_cur!=(unsigned int *)mask_val.s.s) ) {
		destroy_avp(mask_avp);
		mask_avp = NULL;
	}
	if( mask_avp == NULL ) {
		mask_val.s.s = (char *)dst_bitmap_cur;
		mask_val.s.len = bitmap_size_cur * sizeof(unsigned int);
		if( add_avp(AVP_VAL_STR, mask_avp_name, mask_val) != 0 ) {
			LM_ERR("failed to add MASK AVP\n");
		}
	}
	/* save state - dst, save only if we have one */
	if( id_avp == NULL ) {
		if( dst != NULL ) {
			id_val.n = dst->id;
			if( add_avp(0, id_avp_name, id_val) != 0 ) {
				LM_ERR("failed to add ID AVP\n");
			}
		}
	} else {
		if( dst != NULL ) {
			id_avp->data = (void *)(long)dst->id;
		} else {
			destroy_avp(id_avp);
			id_avp = NULL;
		}
	}
	/* save state - res */
	/* iterate AVPs once and delete old resources */
	destroy_avps(0, res_avp_name, 1 /*all*/);
	/* add new resources */
	for( i=0 ; i<res_cur_n ; i++ ) {
		res_val.s = res_cur[i]->name;
		if( add_avp(AVP_VAL_STR, res_avp_name, res_val) != 0 )
			LM_ERR("failed to add RES AVP\n");
	}

	/* outcome: set dst uri */
	if( (dst != NULL) && (set_dst_uri(req, &dst->uri) != 0) ) {
		LM_ERR("failed to set duri\n");
		return -2;
	}

	return dst ? 0 : -2;
}
Example #19
0
/*
 * Lookup contact in the database and rewrite Request-URI
 */
int lookup(struct sip_msg* _m, char* _t, char* _s)
{
	urecord_t* r;
	str aor, uri;
	ucontact_t* ptr;
	int res;
	int bflags;

	if (_m->new_uri.s) uri = _m->new_uri;
	else uri = _m->first_line.u.request.uri;
	
	if (extract_aor(&uri, &aor) < 0) {
		LOG(L_ERR, "lookup(): Error while extracting address of record\n");
		return -1;
	}
	
	get_act_time();

	ul.lock_udomain((udomain_t*)_t);
	res = ul.get_urecord((udomain_t*)_t, &aor, &r);
	if (res < 0) {
		LOG(L_ERR, "lookup(): Error while querying usrloc\n");
		ul.unlock_udomain((udomain_t*)_t);
		return -2;
	}
	
	if (res > 0) {
		DBG("lookup(): '%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
		ul.unlock_udomain((udomain_t*)_t);
		return -3;
	}

	ptr = r->contacts;
	while ((ptr) && !VALID_CONTACT(ptr, act_time))
		ptr = ptr->next;
	
	if (ptr) {
		if (rewrite_uri(_m, &ptr->c) < 0) {
			LOG(L_ERR, "lookup(): Unable to rewrite Request-URI\n");
			ul.unlock_udomain((udomain_t*)_t);
			return -4;
		}

		if (ptr->received.s && ptr->received.len) {
			if (set_dst_uri(_m, &ptr->received) < 0) {
				ul.unlock_udomain((udomain_t*)_t);
				return -4;
			}
		}

		set_ruri_q(ptr->q);

		/* for RURI branch, the nat flag goes into msg */
		if ( ptr->flags&FL_NAT )
			_m->flags |= nat_flag;

		if (ptr->sock)
			_m->force_send_socket = ptr->sock;

		ptr = ptr->next;
	} else {
		/* All contacts expired */
		ul.unlock_udomain((udomain_t*)_t);
		return -5;
	}

	/* Append branches if enabled */
	if (!append_branches) goto skip;

	for( ; ptr ; ptr = ptr->next ) {
		if (VALID_CONTACT(ptr, act_time)) {
			/* for additional branches, the nat flag goes into dset */
			bflags = (use_branch_flags && (ptr->flags & FL_NAT))?nat_flag:0;
			if (append_branch(_m, &ptr->c, &ptr->received, ptr->q,
			bflags, ptr->sock) == -1) {
				LOG(L_ERR, "lookup(): Error while appending a branch\n");
				/* Return 1 here so the function succeeds even if
				 * appending of a branch failed */
				/* Also give a chance to the next branches*/
				continue;
			}
			if (!use_branch_flags && (ptr->flags & FL_NAT))
				_m->flags |= nat_flag;
		}
	}

skip:
	ul.unlock_udomain((udomain_t*)_t);
	return 1;
}
Example #20
0
static int ul_contact_event_to_msg(struct sip_msg *req)
{
	static enum ul_attrs { UL_URI, UL_RECEIVED, UL_PATH, UL_QVAL,
		UL_SOCKET, UL_BFLAGS, UL_ATTR, UL_MAX } ul_attr;
	/* keep the names of the AVPs aligned with the contact-related events
	 * from USRLOC module !!!! */
	static str ul_names[UL_MAX]= {str_init("uri"),str_init("received"),
	                              str_init("path"),str_init("qval"),
	                              str_init("socket"),str_init("bflags"),
	                              str_init("attr") };
	static int avp_ids[UL_MAX] = { -1, -1, -1, -1, -1, -1, -1};
	int_str vals[UL_MAX];
	int proto, port;
	str host;
	str path_dst;

	if (avp_ids[0]==-1) {
		/* init the avp IDs mapping us on the UL event */
		for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ){
			if (parse_avp_spec( &ul_names[ul_attr], &avp_ids[ul_attr])<0) {
				LM_ERR("failed to init UL AVP %d/%s\n",
					ul_attr,ul_names[ul_attr].s);
				avp_ids[0] = -1;
				return -1;
			}
		}
	}

	/* fetch the AVP values one by one */
	for( ul_attr=0 ; ul_attr<UL_MAX ; ul_attr++ ) {
		if (search_first_avp(0, avp_ids[ul_attr], &vals[ul_attr], NULL)==NULL){
			LM_ERR("cannot find AVP(%d) for event attr %d/%s\n",
				avp_ids[ul_attr], ul_attr, ul_names[ul_attr].s);
			return -1;
		}
	}

	/* OK, we have the values, lets inject them into the SIP msg */
	LM_DBG("injecting new branch: uri=<%.*s>, received=<%.*s>,"
		"path=<%.*s>, qval=%d, socket=<%.*s>, bflags=%X, attr=<%.*s>\n",
		vals[UL_URI].s.len, vals[UL_URI].s.s,
		vals[UL_RECEIVED].s.len, vals[UL_RECEIVED].s.s,
		vals[UL_PATH].s.len, vals[UL_PATH].s.s,
		vals[UL_QVAL].n,
		vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s,
		vals[UL_BFLAGS].n,
		vals[UL_ATTR].s.len, vals[UL_ATTR].s.s);

	/* contact URI goes as RURI */
	if (set_ruri( req, &vals[UL_URI].s)<0) {
		LM_ERR("failed to set new RURI\n");
		return -1;
	}

	/* contact PATH goes as path */
	if (vals[UL_PATH].s.len) {
		if (get_path_dst_uri(&vals[UL_PATH].s, &path_dst) < 0) {
			LM_ERR("failed to get dst_uri for Path\n");
			return -1;
		}
		if (set_dst_uri( req, &path_dst) < 0) {
			LM_ERR("failed to set dst_uri of Path\n");
			return -1;
		}

		if (set_path_vector( req, &vals[UL_PATH].s)<0) {
			LM_ERR("failed to set PATH\n");
			return -1;
		}
	} else
	/* contact RECEIVED goes as DURI */
	if (vals[UL_RECEIVED].s.len) {
		if (set_dst_uri( req, &vals[UL_RECEIVED].s)<0) {
			LM_ERR("failed to set DST URI\n");
			return -1;
		}
	}

	/* contact Qval goes as RURI Qval */
	set_ruri_q( req, vals[UL_QVAL].n);

	/* contact BFLAGS goes as RURI bflags */
	setb0flags( req, vals[UL_BFLAGS].n);

	/* socket info */
	if (vals[UL_SOCKET].s.len) {
		if ( parse_phostport( vals[UL_SOCKET].s.s, vals[UL_SOCKET].s.len,
		&host.s, &host.len, &port, &proto) < 0) {
			LM_ERR("failed to parse socket from Event attr <%.*s>\n",
				vals[UL_SOCKET].s.len, vals[UL_SOCKET].s.s);
		} else {
			req->force_send_socket = grep_sock_info( &host,
				(unsigned short)port, (unsigned short)proto);
		}
	}

	return 0;
}
Example #21
0
/*!
 * \brief Apply DP-DDDS policy to current SIP message
 *
 * Apply DP-DDDS policy to current SIP message. This means
 * build a new destination URI from the policy AVP and export it
 * as AVP. Then in kamailio.cfg this new target AVP can be pushed
 * into the destination URI $duri
 * \param _msg SIP message
 * \param _s1 unused
 * \param _s2 unused
 * \return negative on failure, positive on succes
 */
int dp_apply_policy(struct sip_msg* _msg, char* _s1, char* _s2) {

	str *domain;
	int_str val;
	struct usr_avp *avp;

	char duri[MAX_URI_SIZE];
	str duri_str;
	int len, didsomething;
	char *at; /* pointer to current location inside duri */

	str host;
	int port, proto;
	struct socket_info* si;

	if (!is_route_type(REQUEST_ROUTE)) {
		LM_ERR("unsupported route type\n");
		return -1;
	}

	/*
	 * set the send_socket
	 */

	/* search for send_socket AVP */
	avp = search_first_avp(send_socket_avp_name_str, send_socket_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string send_socket_avp, "
					"return with error ...\n");
			return -1;
		}
		LM_DBG("send_socket_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		/* parse phostport - AVP str val is asciiz */
		/* FIXME: This code relies on the fact that the string value of an AVP
		 * is zero terminated, which may or may not be true in the future */
		if (parse_phostport(val.s.s, &(host.s), &(host.len), &port, &proto)) {
			LM_ERR("could not parse send_socket, return with error ...\n");
			return -1;
		}
		si = grep_sock_info( &host, (unsigned short) port, (unsigned short) proto);
		if (si) {
			set_force_socket(_msg, si);
		} else {
			LM_WARN("could not find socket for"
					"send_socket '%.*s'\n", val.s.len, ZSW(val.s.s));
		}
	} else {
		LM_DBG("send_socket_avp not found\n");
	}

	/*
	 * set the destination URI
	 */

	didsomething = 0; /* if no AVP is set, there is no need to set the DURI in the end */
	
	if (parse_sip_msg_uri(_msg) < 0) {
		LM_ERR("failed to parse R-URI\n");
		return -1;
	}

	at = (char *)&(duri[0]);
	len = 0;
	if ( (len + 4) >  MAX_URI_SIZE) {
		LM_ERR("duri buffer to small to add uri schema\n");
		return -1;
	}
	memcpy(at, "sip:", 4); at = at + 4; len = len + 4;

	domain = &(_msg->parsed_uri.host);
	LM_DBG("domain is %.*s.\n", domain->len, ZSW(domain->s));

	/* search for prefix and add it to duri buffer */
	avp = search_first_avp(domain_prefix_avp_name_str, domain_prefix_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_prefix_avp, return with error ...\n");
			return -1;
		}
		LM_DBG("domain_prefix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain prefix\n");
			return -1;
		}
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		*at = '.'; at = at + 1;	/* add . as delimiter between prefix and domain */
		didsomething = 1;
	} else {
		LM_DBG("domain_prefix_avp not found\n");
	}


	/* add domain to duri buffer */
	avp = search_first_avp(domain_replacement_avp_name_str, domain_replacement_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_replacement_avp, return with"
					"error ...\n");
			return -1;
		}
		LM_DBG("domain_replacement_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len +1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain replacement\n");
			return -1;
		}
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
	    LM_DBG("domain_replacement_avp not found, using original domain '"
				"%.*s'\n",domain->len, domain->s);
	    if ( (len + domain->len) >  MAX_URI_SIZE) {
		LM_ERR("duri buffer to small to add domain\n");
		return -1;
	    }
	    memcpy(at, domain->s, domain->len); at = at + domain->len;
	}
	
	/* search for suffix and add it to duri buffer */
	avp = search_first_avp(domain_suffix_avp_name_str, domain_suffix_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string domain_suffix_avp,return with error .."
					"\n");
			return -1;
		}
		LM_DBG("domain_suffix_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain suffix\n");
			return -1;
		}
		*at = '.'; at = at + 1;	/* add . as delimiter between domain and suffix */
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("domain_suffix_avp not found\n");
	}

	/* search for port override and add it to duri buffer */
	avp = search_first_avp(port_override_avp_name_str, port_override_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string port_override_avp, return with error ...\n");
			return -1;
		}
		LM_DBG("port_override_avp found = '%.*s'\n", val.s.len, ZSW(val.s.s));
		/* We do not check if the port is valid */
		if ( (len + val.s.len + 1) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add domain suffix\n");
			return -1;
		}
		*at = ':'; at = at + 1;	/* add : as delimiter between domain and port */
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("port_override_avp not found, using original port\n");
		if (_msg->parsed_uri.port.len) {
			LM_DBG("port found in RURI, reusing it for DURI\n");
			if ( (len + _msg->parsed_uri.port.len + 1) >  MAX_URI_SIZE) {
				LM_ERR("duri buffer to small to copy port\n");
				return -1;
			}
			*at = ':'; at = at + 1;	
			/* add : as delimiter between domain and port */
			memcpy(at, _msg->parsed_uri.port.s, _msg->parsed_uri.port.len); 
			at = at + _msg->parsed_uri.port.len;
		} else {
			LM_DBG("port not found in RURI, no need to copy it to DURI\n");
		}
	}

	/* search for transport override and add it to duri buffer */
	avp = search_first_avp(transport_override_avp_name_str, transport_override_name, &val, 0);
	if (avp) {
		if ( !(avp->flags&AVP_VAL_STR) ||  !val.s.s || !val.s.len) {
			LM_ERR("empty or non-string transport_override_avp, "
					"return with error ...\n");
			return -1;
		}
		LM_DBG("transport_override_avp found='%.*s'\n",val.s.len, ZSW(val.s.s));

		if ( (len + val.s.len + 11) >  MAX_URI_SIZE) {
			LM_ERR("duri buffer to small to add transport override\n");
			return -1;
		}
		/* add : as transport parameter to duri; NOTE: no checks if transport parameter is valid  */
		memcpy(at, ";transport=", 11); at = at + 11;
		memcpy(at, val.s.s, val.s.len); at = at + val.s.len;
		didsomething = 1;
	} else {
		LM_DBG("transport_override_avp not found, using original transport\n");
		if (_msg->parsed_uri.transport.len) {
			LM_DBG("transport found in RURI, reusing it for DURI\n");
			if ( (len + _msg->parsed_uri.transport.len + 1) >  MAX_URI_SIZE) {
				LM_ERR("duri buffer to small to copy transport\n");
				return -1;
			}
			*at = ';'; at = at + 1; /* add : as delimiter between domain and port */
			memcpy(at, _msg->parsed_uri.transport.s, _msg->parsed_uri.transport.len); at = at + _msg->parsed_uri.transport.len;
		} else {
			LM_DBG("transport not found in RURI, no need to copy it to DURI\n");
		}
	}

	/* write new target DURI into DURI */
	if (didsomething == 0) {
		LM_DBG("no domainpolicy AVP set, no need to push new DURI\n");
		return 2;
	}
	duri_str.s = (char *)&(duri[0]);
	duri_str.len = at - duri_str.s;
	LM_DBG("new DURI is '%.*s'\n",duri_str.len, ZSW(duri_str.s));
	if(set_dst_uri(_msg, &duri_str)<0) {
		LM_ERR("failed to se dst uri\n");
		return -1;
	}
	/* dst_uri changes, so it makes sense to re-use the current uri for
		forking */
	ruri_mark_new(); /* re-use uri for serial forking */

	return 1;
}
Example #22
0
/*!
 * \brief Previous hop was a strict router, handle this case
 * \param _m SIP message
 * \return -1 on error, 1 on success
 */
static inline int after_strict(struct sip_msg* _m)
{
    int res, rem_len;
    struct hdr_field* hdr;
    struct sip_uri puri;
    rr_t* rt, *prev;
    char* rem_off;
    str uri;
    struct socket_info *si;

    hdr = _m->route;
    rt = (rr_t*)hdr->parsed;
    uri = rt->nameaddr.uri;

    /* reset rr handling static vars for safety in error case */
    routed_msg_id = 0;
    routed_params.s = NULL;
    routed_params.len = 0;

    if (parse_uri(uri.s, uri.len, &puri) < 0) {
        LM_ERR("failed to parse the first route URI\n");
        return RR_ERROR;
    }

    if ( enable_double_rr && is_2rr(&puri.params) && is_myself(&puri)) {
        /* double route may occure due different IP and port, so force as
         * send interface the one advertise in second Route */
        si = grep_sock_info( &puri.host, puri.port_no, puri.proto);
        if (si) {
            set_force_socket(_m, si);
        } else {
            if (enable_socket_mismatch_warning)
                LM_WARN("no socket found for match second RR\n");
        }

        if (!rt->next) {
            /* No next route in the same header, remove the whole header
             * field immediately
             */
            if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
                LM_ERR("failed to remove Route HF\n");
                return RR_ERROR;
            }
            res = find_next_route(_m, &hdr);
            if (res < 0) {
                LM_ERR("searching next route failed\n");
                return RR_ERROR;
            }
            if (res > 0) { /* No next route found */
                LM_DBG("after_strict: No next URI found\n");
                return NOT_RR_DRIVEN;
            }
            rt = (rr_t*)hdr->parsed;
        } else rt = rt->next;

        /* parse the new found uri */
        uri = rt->nameaddr.uri;
        if (parse_uri(uri.s, uri.len, &puri) < 0) {
            LM_ERR("failed to parse URI\n");
            return RR_ERROR;
        }
    }

    /* set the hooks for the param
     * important note: RURI is already parsed by the above function, so
     * we just used it without any checking */
    routed_msg_id = _m->id;
    routed_params = _m->parsed_uri.params;

    if (is_strict(&puri.params)) {
        LM_DBG("Next hop: '%.*s' is strict router\n", uri.len, ZSW(uri.s));
        /* Previous hop was a strict router and the next hop is strict
         * router too. There is no need to save R-URI again because it
         * is saved already. In fact, in this case we will behave exactly
         * like a strict router. */

        /* Note: when there is only one Route URI left (endpoint), it will
         * always be a strict router because endpoints don't use ;lr parameter
         * In this case we will simply put the URI in R-URI and forward it,
         * which will work perfectly */
        if(get_maddr_uri(&uri, &puri)!=0) {
            LM_ERR("failed to check maddr\n");
            return RR_ERROR;
        }
        if (rewrite_uri(_m, &uri) < 0) {
            LM_ERR("failed to rewrite request URI\n");
            return RR_ERROR;
        }

        if (rt->next) {
            rem_off = hdr->body.s;
            rem_len = rt->next->nameaddr.name.s - hdr->body.s;
        } else {
            rem_off = hdr->name.s;
            rem_len = hdr->len;
        }
        if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) {
            LM_ERR("failed to remove Route HF\n");
            return RR_ERROR;
        }
    } else {
        LM_DBG("Next hop: '%.*s' is loose router\n",
               uri.len, ZSW(uri.s));

        if(get_maddr_uri(&uri, &puri)!=0) {
            LM_ERR("failed to check maddr\n");
            return RR_ERROR;
        }
        if (set_dst_uri(_m, &uri) < 0) {
            LM_ERR("failed to set dst_uri\n");
            return RR_ERROR;
        }

        /* Next hop is a loose router - Which means that is is not endpoint yet
         * In This case we have to recover from previous strict routing, that
         * means we have to find the last Route URI and put in in R-URI and
         * remove the last Route URI. */
        if (rt != hdr->parsed) {
            /* There is a previous route uri which was 2nd uri of mine
             * and must be removed here */
            rem_off = hdr->body.s;
            rem_len = rt->nameaddr.name.s - hdr->body.s;
            if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) {
                LM_ERR("failed to remove Route HF\n");
                return RR_ERROR;
            }
        }


        res = find_rem_target(_m, &hdr, &rt, &prev);
        if (res < 0) {
            LM_ERR("searching for last Route URI failed\n");
            return RR_ERROR;
        } else if (res > 0) {
            /* No remote target is an error */
            return RR_ERROR;
        }

        uri = rt->nameaddr.uri;
        if(get_maddr_uri(&uri, 0)!=0) {
            LM_ERR("checking maddr failed\n");
            return RR_ERROR;
        }
        if (rewrite_uri(_m, &uri) < 0) {
            LM_ERR("failed to rewrite R-URI\n");
            return RR_ERROR;
        }

        /* The first character if uri will be either '<' when it is the
         * only URI in a Route header field or ',' if there is more than
         * one URI in the header field */
        LM_DBG("The last route URI: '%.*s'\n", rt->nameaddr.uri.len,
               ZSW(rt->nameaddr.uri.s));

        if (prev) {
            rem_off = prev->nameaddr.name.s + prev->len;
            rem_len = rt->nameaddr.name.s + rt->len - rem_off;
        } else {
            rem_off = hdr->name.s;
            rem_len = hdr->len;
        }
        if (!del_lump(_m, rem_off - _m->buf, rem_len, 0)) {
            LM_ERR("failed to remove Route HF\n");
            return RR_ERROR;
        }
    }

    /* run RR callbacks only if we have Route URI parameters */
    if(routed_params.len > 0)
        run_rr_callbacks( _m, &routed_params );

    return RR_DRIVEN;
}
Example #23
0
/*! \brief
 * Lookup contact in the database and rewrite Request-URI
 * \return: -1 : not found
 *          -2 : found but method not allowed
 *          -3 : error
 */
int lookup(struct sip_msg* _m, char* _t, char* _f, char* _s)
{
	unsigned int flags;
	urecord_t* r;
	str aor, uri;
	ucontact_t* ptr,*it;
	int res;
	int ret;
	str path_dst;
	str flags_s;
	char* ua = NULL;
	char* re_end = NULL;
	int re_len = 0;
	char tmp;
	regex_t ua_re;
	int regexp_flags = 0;
	regmatch_t ua_match;
	pv_value_t val;
	int_str istr;
	str sip_instance = {0,0},call_id = {0,0};

	/* branch index */
	int idx;

	/* temporary branch values*/
	int tlen;
	char *turi;

	qvalue_t tq;

	flags = 0;
	if (_f && _f[0]!=0) {
		if (fixup_get_svalue( _m, (gparam_p)_f, &flags_s)!=0) {
			LM_ERR("invalid owner uri parameter");
			return -1;
		}
		for( res=0 ; res< flags_s.len ; res++ ) {
			switch (flags_s.s[res]) {
				case 'm': flags |= REG_LOOKUP_METHODFILTER_FLAG; break;
				case 'b': flags |= REG_LOOKUP_NOBRANCH_FLAG; break;
				case 'r': flags |= REG_BRANCH_AOR_LOOKUP_FLAG; break;
				case 'u':
					if (flags_s.s[res+1] != '/') {
						LM_ERR("no regexp after 'u' flag");
						break;
					}
					res++;
					if ((re_end = strrchr(flags_s.s+res+1, '/')) == NULL) {
						LM_ERR("no regexp after 'u' flag");
						break;
					}
					res++;
					re_len = re_end-flags_s.s-res;
					if (re_len == 0) {
						LM_ERR("empty regexp");
						break;
					}
					ua = flags_s.s+res;
					flags |= REG_LOOKUP_UAFILTER_FLAG;
					LM_DBG("found regexp /%.*s/", re_len, ua);
					res += re_len;
					break;
				case 'i': regexp_flags |= REG_ICASE; break;
				case 'e': regexp_flags |= REG_EXTENDED; break;
				default: LM_WARN("unsuported flag %c \n",flags_s.s[res]);
			}
		}
	}
	if (flags&REG_BRANCH_AOR_LOOKUP_FLAG) {
		/* extract all the branches for further usage */
		nbranches = 0;
		while (
			(turi=get_branch(nbranches, &tlen, &tq, NULL, NULL, NULL, NULL))
				) {
			/* copy uri */
			branch_uris[nbranches].s = urimem[nbranches];
			if (tlen) {
				memcpy(branch_uris[nbranches].s, turi, tlen);
				branch_uris[nbranches].len = tlen;
			} else {
				*branch_uris[nbranches].s  = '\0';
				branch_uris[nbranches].len = 0;
			}

			nbranches++;
		}
		clear_branches();
		idx=0;
	}


	if (_s) {
		if (pv_get_spec_value( _m, (pv_spec_p)_s, &val)!=0) {
			LM_ERR("failed to get PV value\n");
			return -1;
		}
		if ( (val.flags&PV_VAL_STR)==0 ) {
			LM_ERR("PV vals is not string\n");
			return -1;
		}
		uri = val.rs;
	} else {
		if (_m->new_uri.s) uri = _m->new_uri;
		else uri = _m->first_line.u.request.uri;
	}

	if (extract_aor(&uri, &aor,&sip_instance,&call_id) < 0) {
		LM_ERR("failed to extract address of record\n");
		return -3;
	}

	get_act_time();

	ul.lock_udomain((udomain_t*)_t, &aor);
	res = ul.get_urecord((udomain_t*)_t, &aor, &r);
	if (res > 0) {
		LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
		ul.unlock_udomain((udomain_t*)_t, &aor);
		return -1;
	}

	if (flags & REG_LOOKUP_UAFILTER_FLAG) {
		tmp = *(ua+re_len);
		*(ua+re_len) = '\0';
		if (regcomp(&ua_re, ua, regexp_flags) != 0) {
			LM_ERR("bad regexp '%s'\n", ua);
			*(ua+re_len) = tmp;
			return -1;
		}
		*(ua+re_len) = tmp;
	}


	ptr = r->contacts;
	ret = -1;
	/* look first for an un-expired and suported contact */
search_valid_contact:
	while ( (ptr) &&
	!(VALID_CONTACT(ptr,act_time) && (ret=-2) && allowed_method(_m,ptr,flags)))
		ptr = ptr->next;
	if (ptr==0) {
		/* nothing found */
		LM_DBG("nothing found !\n");
		goto done;
	}

	ua_re_check(
		ret = -1;
		ptr = ptr->next;
		goto search_valid_contact
	);

	if (sip_instance.len && sip_instance.s) {
		LM_DBG("ruri has gruu in lookup\n");
		/* uri has GRUU */
		if (ptr->instance.len-2 != sip_instance.len ||
				memcmp(ptr->instance.s+1,sip_instance.s,sip_instance.len)) {
			LM_DBG("no match to sip instace - [%.*s] - [%.*s]\n",ptr->instance.len-2,ptr->instance.s+1,
					sip_instance.len,sip_instance.s);
			/* not the targeted instance, search some more */
			ptr = ptr->next;
			goto search_valid_contact;
		}

		LM_DBG("matched sip instace\n");
	}

	if (call_id.len && call_id.s) {
		/* decide whether GRUU is expired or not
		 *
		 * first - match call-id */
		if (ptr->callid.len != call_id.len ||
				memcmp(ptr->callid.s,call_id.s,call_id.len)) {
			LM_DBG("no match to call id - [%.*s] - [%.*s]\n",ptr->callid.len,ptr->callid.s,
					call_id.len,call_id.s);
			ptr = ptr->next;
			goto search_valid_contact;
		}

		/* matched call-id, check if there are newer contacts with
		 * same sip instace bup newer last_modified */

		it = ptr->next;
		while ( it ) {
			if (VALID_CONTACT(it,act_time)) {
				if (it->instance.len-2 == sip_instance.len && sip_instance.s &&
						memcmp(it->instance.s+1,sip_instance.s,sip_instance.len) == 0)
					if (it->last_modified > ptr->last_modified) {
						/* same instance id, but newer modified -> expired GRUU, no match at all */
						break;
					}
			}
			it=it->next;
		}

		if (it != NULL) {
			ret = -1;
			goto done;
		}
	}

	LM_DBG("found a complete match\n");

	ret = 1;
	if (ptr) {
		LM_DBG("setting as ruri <%.*s>\n",ptr->c.len,ptr->c.s);
		if (set_ruri(_m, &ptr->c) < 0) {
			LM_ERR("unable to rewrite Request-URI\n");
			ret = -3;
			goto done;
		}

		/* If a Path is present, use first path-uri in favour of
		 * received-uri because in that case the last hop towards the uac
		 * has to handle NAT. - agranig */
		if (ptr->path.s && ptr->path.len) {
			if (get_path_dst_uri(&ptr->path, &path_dst) < 0) {
				LM_ERR("failed to get dst_uri for Path\n");
				ret = -3;
				goto done;
			}
			if (set_path_vector(_m, &ptr->path) < 0) {
				LM_ERR("failed to set path vector\n");
				ret = -3;
				goto done;
			}
			if (set_dst_uri(_m, &path_dst) < 0) {
				LM_ERR("failed to set dst_uri of Path\n");
				ret = -3;
				goto done;
			}
		} else if (ptr->received.s && ptr->received.len) {
			if (set_dst_uri(_m, &ptr->received) < 0) {
				ret = -3;
				goto done;
			}
		}

		set_ruri_q( _m, ptr->q);

		setbflag( _m, 0, ptr->cflags);

		if (ptr->sock)
			_m->force_send_socket = ptr->sock;

		/* populate the 'attributes' avp */
		if (attr_avp_name != -1) {
			istr.s = ptr->attr;
			if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) {
				LM_ERR("Failed to populate attr avp!\n");
			}
		}

		ptr = ptr->next;
	}

	/* Append branches if enabled */
	/* If we got to this point and the URI had a ;gr parameter and it was matched
	 * to a contact. No point in branching */
	if ( flags&REG_LOOKUP_NOBRANCH_FLAG || (sip_instance.len && sip_instance.s) ) goto done;
	LM_DBG("looking for branches\n");

	do {
		for( ; ptr ; ptr = ptr->next ) {
			if (VALID_CONTACT(ptr, act_time) && allowed_method(_m,ptr,flags)) {
				path_dst.len = 0;
				if(ptr->path.s && ptr->path.len
				&& get_path_dst_uri(&ptr->path, &path_dst) < 0) {
					LM_ERR("failed to get dst_uri for Path\n");
					continue;
				}

				ua_re_check(continue);

				/* The same as for the first contact applies for branches
				 * regarding path vs. received. */
				LM_DBG("setting branch <%.*s>\n",ptr->c.len,ptr->c.s);
				if (append_branch(_m,&ptr->c,path_dst.len?&path_dst:&ptr->received,
				&ptr->path, ptr->q, ptr->cflags, ptr->sock) == -1) {
					LM_ERR("failed to append a branch\n");
					/* Also give a chance to the next branches*/
					continue;
				}

				/* populate the 'attributes' avp */
				if (attr_avp_name != -1) {
					istr.s = ptr->attr;
					if (add_avp_last(AVP_VAL_STR, attr_avp_name, istr) != 0) {
						LM_ERR("Failed to populate attr avp!\n");
					}
				}
			}
		}
		/* 0 branches condition also filled; idx initially -1*/
		if (!(flags&REG_BRANCH_AOR_LOOKUP_FLAG) || idx == nbranches)
			goto done;


		/* relsease old aor lock */
		ul.unlock_udomain((udomain_t*)_t, &aor);
		ul.release_urecord(r, 0);

		/* idx starts from -1 */
		uri = branch_uris[idx];
		if (extract_aor(&uri, &aor, NULL, &call_id) < 0) {
			LM_ERR("failed to extract address of record for branch uri\n");
			return -3;
		}

		/* release old urecord */

		/* get lock on new aor */
		LM_DBG("getting contacts from aor [%.*s]"
					"in branch %d\n", aor.len, aor.s, idx);
		ul.lock_udomain((udomain_t*)_t, &aor);
		res = ul.get_urecord((udomain_t*)_t, &aor, &r);

		if (res > 0) {
			LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
			goto done;
		}
		idx++;
		ptr = r->contacts;
	} while (1);
Example #24
0
int ds_select_dst(struct sip_msg *msg, char *set, char *alg)
{
	int a, s, idx;
	ds_setidx_p si = NULL;
	unsigned int hash;

	if(msg==NULL)
	{
		LOG(L_ERR, "DISPATCHER:ds_select_dst: bad parameters\n");
		return -1;
	}
	
	if(_ds_list==NULL || _ds_index==NULL)
	{
		LOG(L_ERR, "DISPATCHER:ds_select_dst: no destination sets\n");
		return -1;
	}

	if((force_dst==0) && (msg->dst_uri.s!=NULL || msg->dst_uri.len>0))
	{
		LOG(L_ERR,
			"DISPATCHER:ds_select_dst: destination already set [%.*s]\n",
			msg->dst_uri.len, msg->dst_uri.s);
		return -1;
	}
	
	s = (int)(long)set;
	a = (int)(long)alg;

	/* get the index of the set */
	si = _ds_index;
	while(si)
	{
		if(si->id == s)
		{
			idx = si->index;
			break;
		}
		si = si->next;
	}

	if(si==NULL)
	{
		LOG(L_ERR,
			"DISPATCHER:ds_select_dst: destination set [%d] not found\n",s);
		return -1;
	}

	DBG("DISPATCHER:ds_select_dst: set index [%d]\n", idx);

	hash = 0;
	switch(a)
	{
		case 0:
			if(ds_hash_callid(msg, &hash)!=0)
			{
				LOG(L_ERR,
					"DISPATCHER:ds_select_dst: can't get callid hash\n");
				return -1;
			}
		break;
		case 1:
			if(ds_hash_fromuri(msg, &hash)!=0)
			{
				LOG(L_ERR,
					"DISPATCHER:ds_select_dst: can't get From uri hash\n");
				return -1;
			}
		break;
		default:
			hash = 0;
	}

	DBG("DISPATCHER:ds_select_dst: alg hash [%u]\n", hash);

	hash = hash%_ds_list[idx].nr;

	if (set_dst_uri(msg, &_ds_list[idx].dlist[hash].uri) < 0) {
		LOG(L_ERR, "DISPATCHER:dst_select_dst: Error while setting dst_uri\n");
		return -1;
	}

	DBG("DISPATCHER:ds_select_dst: selected [%d-%d/%d/%d] <%.*s>\n",
			a, s, idx, hash, msg->dst_uri.len, msg->dst_uri.s);
	
	return 1;
}
Example #25
0
/*!
 * \brief Perform outbound processing - force local socket and set destination URI
 * \param _m SIP message
 * \param flow_token string containing the flow-token extracted from the Route: header
 * \param dst_uri string to write the destination URI to (extracted from flow-token)
 * \return -1 on error, 0 when outbound not in use, 1 when outbound in use
 */
static inline int process_outbound(struct sip_msg *_m, str flow_token)
{
    int ret;
    struct receive_info *rcv = NULL;
    struct socket_info *si;
    str dst_uri;

    if (!rr_obb.decode_flow_token)
        return 0;

    ret = rr_obb.decode_flow_token(_m, &rcv, flow_token);

    if (ret == -2) {
        LM_DBG("no flow token found - outbound not in use\n");
        return 0;
    } else if (ret == -1) {
        LM_INFO("failed to decode flow token\n");
        return -1;
    } else if (!ip_addr_cmp(&rcv->src_ip, &_m->rcv.src_ip)
               || rcv->src_port != _m->rcv.src_port) {
        LM_DBG("\"incoming\" request found. Using flow-token for"
               "routing\n");

        /* First, force the local socket */
        si = find_si(&rcv->dst_ip, rcv->dst_port, rcv->proto);
        if (si)
            set_force_socket(_m, si);
        else {
            LM_INFO("cannot find socket from flow-token\n");
            return -1;
        }

        /* Second, override the destination URI */
        dst_uri.s = uri_buf;
        dst_uri.len = 0;

        dst_uri.len += snprintf(dst_uri.s + dst_uri.len,
                                MAX_ROUTE_URI_LEN - dst_uri.len,
                                "sip:%s",
                                rcv->src_ip.af == AF_INET6 ? "[" : "");
        dst_uri.len += ip_addr2sbuf(&rcv->src_ip,
                                    dst_uri.s + dst_uri.len,
                                    MAX_ROUTE_URI_LEN - dst_uri.len);
        dst_uri.len += snprintf(dst_uri.s + dst_uri.len,
                                MAX_ROUTE_URI_LEN - dst_uri.len,
                                "%s:%d;transport=%s",
                                rcv->src_ip.af == AF_INET6 ? "]" : "",
                                rcv->src_port,
                                get_proto_name(rcv->proto));

        if (set_dst_uri(_m, &dst_uri) < 0) {
            LM_ERR("failed to set dst_uri\n");
            return -1;
        }
        ruri_mark_new();

        return 1;
    }

    LM_DBG("Not using flow-token for routing\n");
    return 0;
}
Example #26
0
int sbranch_set_ruri(sip_msg_t *msg)
{
	str sv;
	flag_t old_bflags;
	branch_t *br;
	int ret;

	ret = 0;
	br = &_pv_sbranch;
	if(br->len==0)
		return -1;

	sv.s = br->uri;
	sv.len = br->len;

	if (rewrite_uri(msg, &sv) < 0) {
		LM_ERR("unable to rewrite Request-URI\n");
		ret = -3;
		goto error;
	}

	/* reset next hop address */
	reset_dst_uri(msg);
	if(br->dst_uri_len>0) {
		sv.s = br->dst_uri;
		sv.len = br->dst_uri_len;
		if (set_dst_uri(msg, &sv) < 0) {
			ret = -3;
			goto error;
		}
	}

	reset_path_vector(msg);
	if(br->path_len==0) {
		sv.s = br->path;
		sv.len = br->path_len;
		if(set_path_vector(msg, &sv) < 0) {
			ret = -4;
			goto error;
		}
	}

	reset_instance(msg);
	if (br->instance_len) {
		sv.s = br->instance;
		sv.len = br->instance_len;
	    if (set_instance(msg, &sv) < 0) {
			ret = -5;
			goto error;
	    }
	}

	reset_ruid(msg);
	if (br->ruid_len) {
		sv.s = br->ruid;
		sv.len = br->ruid_len;
	    if (set_ruid(msg, &sv) < 0) {
			ret = -6;
			goto error;
	    }
	}

	reset_ua(msg);
	if (br->location_ua_len) {
		sv.s = br->location_ua;
		sv.len = br->location_ua_len;
	    if (set_ua(msg, &sv) < 0) {
			ret = -7;
			goto error;
	    }
	}

	if (br->force_send_socket)
		set_force_socket(msg, br->force_send_socket);

	msg->reg_id = br->reg_id;
	set_ruri_q(br->q);
	old_bflags = 0;
	getbflagsval(0, &old_bflags);
	setbflagsval(0, old_bflags|br->flags);

	return 0;
error:
	return ret;
}
Example #27
0
/*!
 * \brief Previous hop was a loose router, handle this case
 * \param _m SIP message
 * \param preloaded do we have a preloaded route set
 * \return -1 on failure, 1 on success
 */
static inline int after_loose(struct sip_msg* _m, int preloaded)
{
    struct hdr_field* hdr;
    struct sip_uri puri;
    rr_t* rt;
    int res;
    int status = RR_DRIVEN;
    str uri;
    struct socket_info *si;
    int uri_is_myself, next_is_strict;
    int use_ob = 0;

    hdr = _m->route;
    rt = (rr_t*)hdr->parsed;
    uri = rt->nameaddr.uri;

    /* reset rr handling static vars for safety in error case */
    routed_msg_id = 0;

    if (parse_uri(uri.s, uri.len, &puri) < 0) {
        LM_ERR("failed to parse the first route URI\n");
        return RR_ERROR;
    }

    next_is_strict = is_strict(&puri.params);
    routed_params = puri.params;
    uri_is_myself = is_myself(&puri);

    /* IF the URI was added by me, remove it */
    if (uri_is_myself>0)
    {
        LM_DBG("Topmost route URI: '%.*s' is me\n",
               uri.len, ZSW(uri.s));
        /* set the hooks for the params */
        routed_msg_id = _m->id;

        if ((use_ob = process_outbound(_m, puri.user)) < 0) {
            LM_INFO("failed to process outbound flow-token\n");
            return FLOW_TOKEN_BROKEN;
        }

        if (!rt->next) {
            /* No next route in the same header, remove the whole header
             * field immediately
             */
            if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
                LM_ERR("failed to remove Route HF\n");
                return RR_ERROR;
            }

            res = find_next_route(_m, &hdr);
            if (res < 0) {
                LM_ERR("failed to find next route\n");
                return RR_ERROR;
            }
            if (res > 0) { /* No next route found */
                LM_DBG("No next URI found\n");
                status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);
                goto done;
            }
            rt = (rr_t*)hdr->parsed;
        } else rt = rt->next;

        if (enable_double_rr && is_2rr(&puri.params)) {
            /* double route may occure due different IP and port, so force as
             * send interface the one advertise in second Route */
            if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) {
                LM_ERR("failed to parse the double route URI\n");
                return RR_ERROR;
            }

            if (!use_ob) {
                si = grep_sock_info( &puri.host, puri.port_no, puri.proto);
                if (si) {
                    set_force_socket(_m, si);
                } else {
                    if (enable_socket_mismatch_warning)
                        LM_WARN("no socket found for match second RR\n");
                }
            }

            if (!rt->next) {
                /* No next route in the same header, remove the whole header
                 * field immediately */
                if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
                    LM_ERR("failed to remove Route HF\n");
                    return RR_ERROR;
                }
                res = find_next_route(_m, &hdr);
                if (res < 0) {
                    LM_ERR("failed to find next route\n");
                    return RR_ERROR;
                }
                if (res > 0) { /* No next route found */
                    LM_DBG("no next URI found\n");
                    status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);
                    goto done;
                }
                rt = (rr_t*)hdr->parsed;
            } else rt = rt->next;
        }

        uri = rt->nameaddr.uri;
        if (parse_uri(uri.s, uri.len, &puri) < 0) {
            LM_ERR("failed to parse the first route URI\n");
            return RR_ERROR;
        }
    } else {
#ifdef ENABLE_USER_CHECK
        /* check if it the ignored user */
        if(uri_is_myself < 0)
            return NOT_RR_DRIVEN;
#endif
        LM_DBG("Topmost URI is NOT myself\n");
        routed_params.s = NULL;
        routed_params.len = 0;
    }

    LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s));
    if (next_is_strict) {
        LM_DBG("Next URI is a strict router\n");
        if (handle_sr(_m, hdr, rt) < 0) {
            LM_ERR("failed to handle strict router\n");
            return RR_ERROR;
        }
    } else {
        /* Next hop is loose router */
        LM_DBG("Next URI is a loose router\n");

        if (!use_ob) {
            if(get_maddr_uri(&uri, &puri)!=0) {
                LM_ERR("checking maddr failed\n");
                return RR_ERROR;
            }

            if (set_dst_uri(_m, &uri) < 0) {
                LM_ERR("failed to set dst_uri\n");
                return RR_ERROR;
            }
            /* dst_uri changed, so it makes sense to re-use the current uri for
            forking */
            ruri_mark_new(); /* re-use uri for serial forking */
        }

        /* There is a previous route uri which was 2nd uri of mine
         * and must be removed here */
        if (rt != hdr->parsed) {
            if (!del_lump(_m, hdr->body.s - _m->buf,
                          rt->nameaddr.name.s - hdr->body.s, 0)) {
                LM_ERR("failed to remove Route HF\n");
                return RR_ERROR;
            }
        }
    }

done:
    if (use_ob == 1)
        status = RR_OB_DRIVEN;

    /* run RR callbacks only if we have Route URI parameters */
    if(routed_params.len > 0)
        run_rr_callbacks( _m, &routed_params );
    return status;
}
Example #28
0
static inline int after_loose(struct sip_msg* _m, int preloaded)
{
	struct hdr_field* hdr;
	struct sip_uri puri;
	struct sip_uri puri2;
	rr_t* rt;
	int res;
	int status;
#ifdef ENABLE_USER_CHECK
	int ret;
#endif
	str uri;
	struct socket_info *si;
	int force_ss = 0;

	hdr = _m->route;
	rt = (rr_t*)hdr->parsed;
	uri = rt->nameaddr.uri;

	if (parse_uri(uri.s, uri.len, &puri) < 0) {
		LM_ERR("failed to parse the first route URI\n");
		return RR_ERROR;
	}

	/* IF the URI was added by me, remove it */
#ifdef ENABLE_USER_CHECK
	ret=is_myself(&puri.user, &puri.host, puri.port_no);
	if (ret>0)
#else
	if (is_myself(&puri.host, puri.port_no))
#endif
	{
		LM_DBG("Topmost route URI: '%.*s' is me\n",
			uri.len, ZSW(uri.s));
		/* set the hooks for the params -bogdan */
		ctx_rrparam_set( &puri.params );

		/* if last route in header, gonna get del_lumped now,
		 * if not, it will be taken care of later
		 * Mark it now as deleted */
		rt->deleted = 1;

		if (!rt->next) {
			/* No next route in the same header, remove the whole header
			 * field immediately
			 */
			if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
				LM_ERR("failed to remove Route HF\n");
				return RR_ERROR;
			}

			rt->deleted = 1;

			res = find_next_route(_m, &hdr);
			if (res < 0) {
				LM_ERR("failed to find next route\n");
				return RR_ERROR;
			}
			if (res > 0) { /* No next route found */
				LM_DBG("No next URI found!\n");
				status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);

				/*same case as LL , if there is no next route*/
				ctx_routing_set( ROUTING_LL );
				force_ss = 1;

				goto done;
			}
			rt = (rr_t*)hdr->parsed;
		} else rt = rt->next;

		if (enable_double_rr && is_2rr(&puri.params)) {
			force_ss = 0;
			/* double route may occure due different IP and port, so force as
			 * send interface the one advertise in second Route */
			if (parse_uri(rt->nameaddr.uri.s,rt->nameaddr.uri.len,&puri)<0) {
				LM_ERR("failed to parse the double route URI\n");
				return RR_ERROR;
			}
			set_sip_defaults( puri.port_no, puri.proto);
			si = grep_sock_info( &puri.host, puri.port_no, puri.proto);
			if (si) {
				_m->force_send_socket = si;
			} else {
				if (enable_socket_mismatch_warning)
					LM_WARN("no socket found to match 2nd RR [%d][%.*s:%d]\n",
						puri.proto, puri.host.len, puri.host.s, puri.port_no);
			}

			rt->deleted = 1;

			if (!rt->next) {
				/* No next route in the same header, remove the whole header
				 * field immediately */
				if (!del_lump(_m, hdr->name.s - _m->buf, hdr->len, 0)) {
					LM_ERR("failed to remove Route HF\n");
					return RR_ERROR;
				}

				res = find_next_route(_m, &hdr);
				if (res < 0) {
					LM_ERR("failed to find next route\n");
					return RR_ERROR;
				}
				if (res > 0) { /* No next route found */
					LM_DBG("no next URI found\n");
					status = (preloaded ? NOT_RR_DRIVEN : RR_DRIVEN);

					/* same case as LL , if there is no next route */
					ctx_routing_set( ROUTING_LL );

					goto done;
				}
				rt = (rr_t*)hdr->parsed;
			} else rt = rt->next;
		} else {
			force_ss = 1;
		}

		uri = rt->nameaddr.uri;
		if (parse_uri(uri.s, uri.len, &puri2) < 0) {
			LM_ERR("failed to parse the first route URI\n");
			return RR_ERROR;
		}
	} else {
#ifdef ENABLE_USER_CHECK
		/* check if it the ignored user */
		if(ret < 0)
			return NOT_RR_DRIVEN;
#endif
		LM_DBG("Topmost URI is NOT myself\n");
		memcpy(&puri2, &puri, sizeof(struct sip_uri));
	}

	LM_DBG("URI to be processed: '%.*s'\n", uri.len, ZSW(uri.s));
	if (is_strict(&puri2.params)) {
		LM_DBG("Next URI is a strict router\n");

		ctx_routing_set( ROUTING_LS );
		if (handle_sr(_m, hdr, rt) < 0) {
			LM_ERR("failed to handle strict router\n");
			return RR_ERROR;
		}
	} else {
		/* Next hop is loose router */
		LM_DBG("Next URI is a loose router\n");

		ctx_routing_set( ROUTING_LL );

		if(get_maddr_uri(&uri, &puri2)!=0) {
			LM_ERR("checking maddr failed\n");
			return RR_ERROR;
		}
		if (set_dst_uri(_m, &uri) < 0) {
			LM_ERR("failed to set dst_uri\n");
			return RR_ERROR;
		}

		/* There is a previous route uri which was 2nd uri of mine
		 * and must be removed here */
		if (rt != hdr->parsed) {
			if (!del_lump(_m, hdr->body.s - _m->buf,
			rt->nameaddr.name.s - hdr->body.s, 0)) {
				LM_ERR("failed to remove Route HF\n");
				return RR_ERROR;
			}

			((rr_t *)hdr->parsed)->deleted = 1;
		}
	}
	status = RR_DRIVEN;

done:
	if (force_ss && !preloaded)
		_m->force_send_socket = _m->rcv.bind_address;
	/* run RR callbacks -bogdan */
	run_rr_callbacks( _m, &puri.params );
	return status;
}
Example #29
0
int do_load_balance(struct sip_msg *req, int grp, struct lb_res_str_list *rl,
										unsigned int alg, struct lb_data *data)
{
	static struct lb_resource **call_res = NULL;
	static unsigned int call_res_no = 0;
	static unsigned int *dst_bitmap = NULL;
	static unsigned int bitmap_size = 0;
	unsigned int * used_dst_bitmap;
	struct lb_resource *res;
	int size;
	int i,j;
	unsigned int load, ld;
	struct lb_dst *dst;
	struct lb_dst *it;
	struct lb_dst *last_dst;
	struct usr_avp *grp_avp;
	struct usr_avp *mask_avp;
	struct usr_avp *id_avp;
	int_str grp_val;
	int_str mask_val;
	int_str id_val;

	/* get references to the resources */
	if (rl->n>call_res_no) {
		call_res = (struct lb_resource**)pkg_realloc
			(call_res, rl->n*sizeof(struct lb_resorce*));
		if (call_res==NULL) {
			LM_ERR("no more pkg mem - res ptr realloc\n");
			return -1;
		}
		call_res_no = rl->n;
	}
	for( i=0,res=data->resources ; (i<rl->n)&&res ; res=res->next) {
		if (search_resource_str( rl, &res->name)) {
			call_res[i++] = res;
			LM_DBG("found requested (%d) resource %.*s\n",
				i-1, res->name.len,res->name.s);
		}
	}
	if (i!=rl->n) {
		LM_ERR("unknown resource in input string\n");
		return -1;
	}

	/* any previous iteration due failover ? */
	grp_avp = search_first_avp( 0, grp_avp_name, &grp_val, 0);
	mask_avp = search_first_avp( 0, mask_avp_name, &mask_val, 0);
	id_avp = search_first_avp( 0, id_avp_name, &id_val, 0);

	if ( grp_avp && mask_avp && id_avp && ((grp_avp->flags&AVP_VAL_STR)==0) &&
	(mask_avp->flags&AVP_VAL_STR) && ((id_avp->flags&AVP_VAL_STR)==0) ) {
		/* not the first iteration -> use data from AVPs */
		grp = grp_val.n ;
		used_dst_bitmap = (unsigned int*)mask_val.s.s;
		/* set the previous dst as used (not selected) */
		for(last_dst=data->dsts,i=0,j=0 ; last_dst ; last_dst=last_dst->next) {
			if (last_dst->id==id_val.n) {used_dst_bitmap[i] &= ~(1<<j);break;}
			j++;
			if (j==8*sizeof(unsigned int)) {i++;j=0;}
		}
		LM_DBG("sequential call of LB - previous selected dst is %d\n",id_val.n);
	} else {
		/* first iteration for this call */
		grp_avp = mask_avp = id_avp = NULL;
		last_dst = NULL;

		/* search destinations that fulfill the resources */
		for( size=(unsigned int)(-1),i=0 ; i<rl->n ; i++) {
			if (call_res[i]->bitmap_size<size)
				size = call_res[i]->bitmap_size;
		}
		if (size>bitmap_size) {
			dst_bitmap = (unsigned int*)pkg_realloc
				( dst_bitmap, size*sizeof(unsigned int) );
			if (dst_bitmap==NULL) {
				LM_ERR("no more pkg mem - bitmap realloc\n");
				return -1;
			}
			bitmap_size = size;
		}
		memset( dst_bitmap, 0xff , size*sizeof(unsigned int) );
		for( i=0 ; i<rl->n ; i++) {
			for( j=0 ; j<size ; j++)
				dst_bitmap[j] &= call_res[i]->dst_bitmap[j];
		}
		used_dst_bitmap = dst_bitmap;

		/* create dialog */
		if (lb_dlg_binds.create_dlg( req , 0)!=1 ) {
			LM_ERR("failed to create dialog\n");
			return -1;
		}
	} /* end - first LB run */


	/* lock the resources */
	for( i=0 ; i<rl->n ; i++)
		lock_get( call_res[i]->lock );

	/* do the load-balancing */
	load = 0;
	dst = NULL;
	for( it=data->dsts,i=0,j=0 ; it ; it=it->next) {
		if ( (used_dst_bitmap[i] & (1<<j)) && it->group==grp &&
		(it->flags&LB_DST_STAT_DSBL_FLAG)==0 ) {
			/* valid destination (resources & group & status) */
			if ( (ld = get_dst_load(call_res, rl->n, it, alg)) > load) {
				/* computing a max */
				load = ld;
				dst = it;
			}
			LM_DBG("destination <%.*s> selected for LB set with free=%d "
				"(max=%d)\n",it->uri.len, it->uri.s,ld, load);
		} else {
			if (it->group==grp)
				LM_DBG("skipping destination <%.*s> (used=%d , disabled=%d)\n",
					it->uri.len, it->uri.s,
					(used_dst_bitmap[i] & (1<<j))?0:1 , (it->flags&LB_DST_STAT_DSBL_FLAG)?1:0 );
		}
		j++;
		if (j==8*sizeof(unsigned int)) {i++;j=0;}
	}

	/* if re-trying, remove the dialog from previous profiles */
	if (last_dst) {
		for( i=0 ; i<rl->n ; i++) {
			if (lb_dlg_binds.unset_profile( req, &last_dst->profile_id,
			call_res[i]->profile)!=1)
				LM_ERR("failed to remove from profile\n");
		}
	}

	if (dst==NULL) {
		LM_DBG("no destination found\n");
	} else {
		/* add to the profiles */
		for( i=0 ; i<rl->n ; i++) {
			if (lb_dlg_binds.set_profile( req, &dst->profile_id,
			call_res[i]->profile, 0)!=0)
				LM_ERR("failed to add to profile\n");
		}
	}

	/* unlock the resources*/
	for( i=0 ; i<rl->n ; i++)
		lock_release( call_res[i]->lock );

	if (dst) {
		LM_DBG("winning destination <%.*s> selected for LB set with free=%d\n",
			dst->uri.len, dst->uri.s,load);
		/* change (add/edit) the AVPs for the next iteration */
		if (grp_avp==NULL && mask_avp==NULL) {
			grp_val.n = grp;
			if (add_avp( 0, grp_avp_name, grp_val)!=0) {
				LM_ERR("failed to add GRP AVP");
			}
			mask_val.s.s = (char*)used_dst_bitmap;
			mask_val.s.len = bitmap_size*sizeof(unsigned int);
			if (add_avp( AVP_VAL_STR, mask_avp_name, mask_val)!=0) {
				LM_ERR("failed to add MASK AVP");
			}
		}
		if (id_avp) {
			id_avp->data = (void*)(long)dst->id;
		} else {
			id_val.n = dst->id;
			if (add_avp( 0, id_avp_name, id_val)!=0) {
				LM_ERR("failed to add ID AVP");
			}
		}

		/* set dst uri */
		if (set_dst_uri( req, &dst->uri )!=0) {
			LM_ERR("failed to set duri\n");
			return -2;
		}
	}

	return dst?0:-2;
}
Example #30
0
/*
 * Lookup contact in the database and rewrite Request-URI,
 * and filter them by aor
 */
int lookup2(struct sip_msg* msg, char* table, char* p2)
{
	urecord_t* r;
	str uid;
	ucontact_t* ptr;
	int res;
	unsigned int nat;
	str new_uri, aor;
	fparam_t* fp;

	nat = 0;
	fp = (fparam_t*)p2;
	
	if (get_str_fparam(&aor, msg, (fparam_t*)p2) != 0) {
	    ERR("Unable to get the AOR value\n");
	    return -1;
	}

	if (get_to_uid(&uid, msg) < 0) return -1;
	get_act_time();

	ul.lock_udomain((udomain_t*)table);
	res = ul.get_urecord((udomain_t*)table, &uid, &r);
	if (res < 0) {
		ERR("Error while querying usrloc\n");
		ul.unlock_udomain((udomain_t*)table);
		return -2;
	}
	
	if (res > 0) {
		DBG("'%.*s' Not found in usrloc\n", uid.len, ZSW(uid.s));
		ul.unlock_udomain((udomain_t*)table);
		return -3;
	}

	ptr = r->contacts;
	while (ptr && (!VALID_CONTACT(ptr, act_time) || !VALID_AOR(ptr, aor)))
	    ptr = ptr->next;
	
	if (ptr) {
	       if (ptr->received.s && ptr->received.len) {
			if (received_to_uri){
				if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) {
					ERR("Out of memory\n");
					return -4;
				}
			/* replace the msg uri */
			if (msg->new_uri.s) pkg_free(msg->new_uri.s);
			msg->new_uri = new_uri;
			msg->parsed_uri_ok = 0;
			ruri_mark_new();
			goto skip_rewrite_uri;
			} else if (set_dst_uri(msg, &ptr->received) < 0) {
			        ul.unlock_udomain((udomain_t*)table);
				return -4;
			}
		}
		
		if (rewrite_uri(msg, &ptr->c) < 0) {
			ERR("Unable to rewrite Request-URI\n");
			ul.unlock_udomain((udomain_t*)table);
			return -4;
		}

		if (ptr->sock) {
			set_force_socket(msg, ptr->sock);
		}

skip_rewrite_uri:
		set_ruri_q(ptr->q);

		nat |= ptr->flags & FL_NAT;
		ptr = ptr->next;
	} else {
		     /* All contacts expired */
		ul.unlock_udomain((udomain_t*)table);
		return -5;
	}
	
	     /* Append branches if enabled */
	if (!append_branches) goto skip;

	while(ptr) {
		if (VALID_CONTACT(ptr, act_time) && VALID_AOR(ptr, aor)) {
			if (received_to_uri && ptr->received.s && ptr->received.len) {
				if (add_received(&new_uri, &ptr->c, &ptr->received) < 0) {
					ERR("branch: out of memory\n");
					goto cont; /* try to continue */
				}
				if (append_branch(msg, &new_uri, 0, 0, ptr->q, 0, 0) == -1) {
					ERR("Error while appending a branch\n");
					pkg_free(new_uri.s);
					if (ser_error == E_TOO_MANY_BRANCHES) goto skip;
					else goto cont; /* try to continue, maybe we have an
							                   oversized contact */
				}
				pkg_free(new_uri.s); /* append_branch doesn't free it */
			} else {
				if (append_branch(msg, &ptr->c, &ptr->received, 0 /* path */,
									 ptr->q, 0, ptr->sock) == -1) {
					ERR("Error while appending a branch\n");
					goto skip; /* Return OK here so the function succeeds */
				}
			}
			
			nat |= ptr->flags & FL_NAT; 
		} 
cont:
		ptr = ptr->next; 
	}
	
 skip:
	ul.unlock_udomain((udomain_t*)table);
	if (nat) setflag(msg, load_nat_flag);
	return 1;
}