/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/


#include	"memory_debug.h"
#include	"xl.h"
#include	"xlerror.h"
#include	"utils.h"
#include	"gbacrp.h"
#include	"pri_level.h"

XL_SEXP * gb_MPRouting();

SYS_QUEUE rque1,rque1r,rque2,rque3,rque4;

void rq_task1();
void rq_task1r();
void rq_task2();
void rq_task3();
void rq_task4();

void gc_mp_t();
void gc_mp_t_get();
void gc_d_sexp();
void gc_gb_file();
void gc_gb_sexp();

int rque_init_flag;

int test_q1,test_q2,test_q3,test_q4;

void
init_gb_MPRouting(XLISP_ENV * env)
{
	set_env(env,l_string(std_cm,"MPRouting"),
		get_func_prim(gb_MPRouting,FO_NORMAL,0,3,3));

	memset(&rque1,0,sizeof(SYS_QUEUE));
	rque1.flags = QF_FIFO;
	rque1.gc_func = gc_mp_t;
	rque1.gc_get = gc_mp_t_get;
	rque1.key_func = rq_task1;
	rque1.pri = PRI_FETCH;
	setup_queue(&rque1);

	memset(&rque1r,0,sizeof(SYS_QUEUE));
	rque1r.flags = QF_FIFO;
	rque1r.gc_func = gc_mp_t;
	rque1r.gc_get = gc_mp_t_get;
	rque1r.key_func = rq_task1r;
	rque1r.pri = PRI_FETCH;
	setup_queue(&rque1r);

	memset(&rque2,0,sizeof(SYS_QUEUE));
	rque2.flags = QF_FIFO;
	rque2.gc_func = gc_mp_t;
	rque2.gc_get = gc_mp_t_get;
	rque2.key_func = rq_task2;
	rque2.pri = PRI_FETCH;
	setup_queue(&rque2);

	memset(&rque3,0,sizeof(SYS_QUEUE));
	rque3.flags = QF_FIFO;
	rque3.gc_func = gc_mp_t;
	rque3.gc_get = gc_mp_t_get;
	rque3.key_func = rq_task3;
	rque3.pri = PRI_FETCH;
	setup_queue(&rque3);

	memset(&rque4,0,sizeof(SYS_QUEUE));
	rque4.flags = QF_FIFO|QF_HIGH;
	rque4.gc_func = gc_mp_t;
	rque4.gc_get = gc_mp_t_get;
	rque4.key_func = rq_task4;
	rque4.pri = PRI_FETCH;
	setup_queue(&rque4);

	rque_init_flag = 1;
}


void
insert_queue_mp_t(SYS_QUEUE * q,MP_T *n,int wflag)
{
	insert_queue(q,n,wflag);
	if ( q->total_cnt > 6000 )
		er_panic("insert_queue_mp_t");
}

void
gc_mp_t(MP_T * n)
{
	gc_d_sexp(n->d);
	gc_gb_file(n->file);
	gc_gb_sexp(n->remote);
}

void
gc_mp_t_get(MP_T * n)
{
	lock_mem();
	gc_set_nl(n->d,gc_d_sexp);
	gc_set_nl(n->file,gc_gb_file);
	gc_set_nl(n->remote,gc_gb_sexp);
	unlock_mem();
}

XL_SEXP *
get_fit_list(MAP_PATH * mp,int len,int ret_mode)
{
XL_SEXP * ret;
int i;
	if ( ret_mode == MPR_TARGET )
		return get_string(mp[len-1].crd);
	ret = 0;
	for ( i = len-1 ; i >= 0 ; i -- ) {
		ret = cons(get_string(mp[i].crd),ret);
		ret = cons(get_string(mp[i].map),ret);
	}
	return ret;
}

AROUND_LIST *
cmp_around(L_CHAR * crd,AROUND_LIST * a)
{
AROUND_LIST * ret;
	for ( ret = a ; ret ; ret = ret->next )
		if ( l_strcmp(crd,ret->crd) == 0 )
			return ret;
	return 0;
}

int
check_map_ptr(MAP_PATH * mp)
{
int i;
	for ( i = 0 ; i < ACRP_DIR_NOS ; i ++ ) {
		if ( mp->ent.dir[i].hops < 0 )
			continue;
		if ( mp->ent.dir[i].map == 0 )
			continue;
		if ( l_strcmp(mp->ent.dir[i].map,mp->map) == 0 )
			return 0;
	}
	return -1;
}

void
routing_optimize_el(MP_T * n,int * local_ptr,int pos)
{
L_CHAR * start;
MAP_PATH_INFO * mpi;
AROUND_LIST * a, * result;
int i,j,k,sub;

	if ( pos < 0 )
		start = n->start;
	else	start = n->mp_tbl[pos].crd;
/*
if ( localhost_check_str(start,"routing_optimize_el") < 0 ) {
	log_printf(LOG_WARNING,"REMOTE_CK_OPT pos=%i local_ptr=%i\n",
		pos,*local_ptr);
}
*/
	mpi = get_mpi(0,start,MPI_READ);
	if ( mpi == 0 )
		return;
	a = get_mpi_around(mpi);
	if ( a == 0 ) {
		flush_mpi(mpi);
		return;
	}
	flush_mpi(mpi);
	for ( i = n->mp_ptr-1 ; i > pos+1 ; i -- ) {
		result = cmp_around(n->mp_tbl[i].crd,a);
		if ( result )
			goto mutch;
	}
	free_around_list(a);
	return;
mutch:

	sub = i - pos - 1;
	*local_ptr -= sub;
	for ( j = pos+1 ; j < i ; j ++ )
		free_mp_entry(&n->mp_tbl[j]);
	for ( j = pos+1 ; i < n->mp_ptr ; j ++ , i ++ )
		n->mp_tbl[j] = n->mp_tbl[i];
	for ( k = n->mp_ptr - sub ; k < n->mp_ptr ; k ++ )
		reset_mp_entry(&n->mp_tbl[k]);
	if ( check_map_ptr(&n->mp_tbl[pos+1]) )
		d_f_ree(n->mp_tbl[pos+1].map);
	n->mp_tbl[pos+1].map = ll_copy_str(result->map);
	n->mp_ptr = j;
	free_around_list(a);
}

int
local_adjust(MP_T * n,int local_ptr)
{
L_CHAR * u_str;
URL u;
unsigned int ip;
int port;
	ip = get_localhostip();
	port = get_my_port();

	for ( ; local_ptr > 0 ; local_ptr -- ) {
		u_str = n->mp_tbl[local_ptr-1].crd;
		get_url2(&u,u_str);
		if ( cmp_site(u.server,0,u.port,
				0,ip,port) == 0 ) {
			free_url(&u);
			break;
		}
		free_url(&u);
	}
	return local_ptr;
}

void
routing_optimize(MP_T * n,int local_ptr)
{
int i;

	gc_push(0,0,"routing_optimize");
	local_ptr = local_adjust(n,local_ptr);
	gc_pop(0,0);

	for ( i = -1 ; i < local_ptr ; i ++ )
		routing_optimize_el(n,&local_ptr,i);

}

void
routing_result(MP_T * n)
{
XL_SEXP * ret_sexp;

set_cpu_msg(720003);
	switch ( n->ret_sts ) {
	case MPE_FIT:
set_cpu_msg(720004);
		if ( n->target ) {
		URL u1,u2;
			get_url2(&u1,n->target);
			if ( n->mp_ptr )
				get_url2(&u2,n->mp_tbl[n->mp_ptr-1].crd);
			else 	get_url2(&u2,n->start);
			if ( url_cmp(&u1,&u2) ) {
				free_url(&u1);
				free_url(&u2);
				goto no_route;
			}
			free_url(&u1);
			free_url(&u2);
		}
		ret_sexp = get_fit_list(n->mp_tbl,n->mp_ptr,n->ret_mode);
		break;
	case MPE_NO_ROUTE:
	no_route:
set_cpu_msg(720005);
		ret_sexp = get_error(
			n->file,
			n->line,
			XLE_PROTO_NO_ROUTE,
			l_string(std_cm,"MProuting"),
			n_get_string("there is no route of map path"));
		break;
	case MPE_OVER_TTL:
set_cpu_msg(720006);
		ret_sexp = get_error(
			n->file,
			n->line,
			XLE_PROTO_OVER_TTL,
			l_string(std_cm,"MProuting"),
			n_get_string("over time to live"));
		break;
	case MPE_UNKNOWN:
set_cpu_msg(720007);
		ret_sexp = get_error(
			n->file,
			n->line,
			XLE_PROTO_UNKNOWN,
			l_string(std_cm,"MProuting"),
			n_get_string("unknown error"));
		break;
	default:
		er_panic("MProuting");
	}

set_cpu_msg(0);

	if ( get_type(ret_sexp) == XLT_ERROR ) {
		log_print_sexp(LOG_WARNING,"err",ret_sexp,0);
	} 

	set_d_sexp(n->d,ret_sexp);
	free_mp_t(n);
}


XL_SEXP * 
load_meta_routing(int ses,char * mode,L_CHAR * target)
{
XL_SEXP * ret;
XL_SEXP * gt;
L_CHAR * f;
URL u;
void gc_gb_sexp();

	get_url2(&u,target);

	gc_push(0,0,"remote_fetch");
	gt = get_symbol(l_string(std_cm,"Get"));
	set_attribute(gt,
		l_string(std_cm,"mode"),
		l_string(std_cm,mode));

	f = get_url_filepath(&u);

	ret = remote_session(
		gblisp_top_env0,
		ses,
		&u,
		0,
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(List(gt,
			get_string(f),
			-1),
			-1),
		0,0,0);
	d_f_ree(f);

	gc_pop(ret,gc_gb_sexp);
	return ret;
}


void
rq_task1(TKEY d)
{
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
MP_T * n;
URL u;
int local_ip,p;

	que = (SYS_QUEUE *)GET_TKEY(d);
	key = touch_qkey(que);
	if ( key == 0 )
		return;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);


	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	local_ip = get_localhostip();
	p = get_my_port();


	for ( ; ; ) {

		gc_push(0,0,"routing_task");

		n = delete_queue(que,sq_key_cond,key,0);
		if ( n == 0 ) {
			gc_pop(0,0);
			break;
		}

		get_url2(&u,n->target);
		if ( cmp_site(u.server,0,u.port,
				0,local_ip,p) == 0 ) {
			n->target_cid = url2cid(n->target);
			if ( n->target_cid == 0 ) {
				n->ret_sts = MPE_NO_ROUTE;
				routing_result(n);
			}
			else 	insert_queue_mp_t(&rque2,n,1);
		}
		else {
			n->remote = load_meta_routing(ses,"meta",n->target);
			insert_queue_mp_t(&rque1r,n,1);
		}
		free_url(&u);

		gc_pop(0,0);
	}

	release_qkey(que,key);
	d_f_ree(key);

	close_session(ses);
	close_self_interpreter();

}



void
rq_task1r(TKEY d)
{
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
MP_T * n;
XL_SEXP * cid;


	que = (SYS_QUEUE *)GET_TKEY(d);
	key = touch_qkey(que);
	if ( key == 0 )
		return;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);


	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);
	for ( ; ; ) {

		gc_push(0,0,"routing_task");

		n = delete_queue(que,sq_key_cond,key,0);
		if ( n == 0 ) {
			gc_pop(0,0);
			break;
		}

		if ( get_type(n->remote) != XLT_PAIR )
			goto err;
		cid = get_el_by_symbol(n->remote,
				l_string(std_cm,"meta"),
				0);
		if ( get_type(cid) != XLT_PAIR )
			goto err;
		cid = get_el_by_symbol(cid,
				l_string(std_cm,"cid"),
				0);
		if ( get_type(cid) != XLT_PAIR )
			goto err;
		n->target_cid = list2cid(cid);
		if ( n->target_cid == 0 )
			goto err;

		insert_queue_mp_t(&rque2,n,1);

		gc_pop(0,0);
		continue;
	err:
		n->ret_sts = MPE_NO_ROUTE;
		routing_result(n);
		gc_pop(0,0);
	}

	release_qkey(que,key);
	d_f_ree(key);

	close_session(ses);
	close_self_interpreter();

}


void
rq_task2(TKEY d)
{
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
MP_T * n;
URL u;

	que = (SYS_QUEUE *)GET_TKEY(d);
	key = touch_qkey(que);
	if ( key == 0 )
		return;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);


	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);
	for ( ; ; ) {

		gc_push(0,0,"routing_task");

		n = delete_queue(que,sq_key_cond,key,0);
		if ( n == 0 ) {
			gc_pop(0,0);
			break;
		}


		n->ret_sts = MP_routing(ses,
					&n->mp_ptr,
					n->mp_tbl,
					n->ttl,
					n->start,
					n->target_cid,
					n->mode,
					n->option);

		switch ( n->ret_sts ) {
		case MPE_FIT:
			routing_optimize(n,n->mp_ptr);
			routing_result(n);
			break;
		case MPE_OTHER_SITE:
			if ( n->h.key )
				d_f_ree(n->h.key);
			if ( n->mp_ptr == 0 )
				get_url2(&u,n->start);
			else	get_url2(&u,n->mp_tbl[n->mp_ptr-1].crd);
			n->h.key = get_server_key(&u);
			free_url(&u);
			insert_queue_mp_t(&rque3,n,1);
			break;
		default:
			routing_result(n);
			break;
		}
		gc_pop(0,0);
	}

	release_qkey(que,key);
	d_f_ree(key);

	close_session(ses);
	close_self_interpreter();

}


XL_SEXP *
remote_routing_fast(
	int ses,
	MAP_PATH * mp,int ttl,L_CHAR * url,int * target,
	int mode,
	int ret_mode,
	int option)
{
XL_SEXP * ret;
char buf[20];
XL_SEXP * gt;
URL u;

	gt = n_get_symbol("MPRouting");
	if ( mode ) {
		set_attribute(gt,
			l_string(std_cm,"mode"),
			l_string(std_cm,"fast"));
	}
	else {
		set_attribute(gt,
			l_string(std_cm,"mode"),
			l_string(std_cm,"best"));
	}
	if ( ret_mode ) {
		set_attribute(gt,
			l_string(std_cm,"return"),
			l_string(std_cm,"target"));
	}
	else {
		set_attribute(gt,
			l_string(std_cm,"return"),
			l_string(std_cm,"route"));
	}
	if ( option ) {
		set_attribute(gt,
			l_string(std_cm,"trigger"),
			l_string(std_cm,"on"));
	}
	else {
		set_attribute(gt,
			l_string(std_cm,"trigger"),
			l_string(std_cm,"off"));
	}
	sprintf(buf,"%i",ttl);
	set_attribute(gt,
		l_string(std_cm,"ttl"),
		l_string(std_cm,buf));
	get_url2(&u,url);
	ret = remote_session(
		gblisp_top_env0,
		ses,
		&u,
		l_string(std_cm,"gbstd"),
		l_string(std_cm,"user"),
		l_string(std_cm,"Get"),
		List(
			List(gt,
				get_string(url),
				List(	n_get_symbol("quote"),
					cid2list(target),
					-1),
				-1),
			-1),
		0,0,0);
	free_url(&u);
	return ret;
}


int
remote_routing_result(XL_SEXP * s,MAP_PATH * mp,int ttl,MP_T * n)
{
int mp_ptr;
XL_SEXP * t;

	if ( get_type(s) == XLT_ERROR ) {
		return MPE_NO_ROUTE;
	}
	if ( n->ret_mode == MPR_TARGET ) {
		if ( get_type(s) != XLT_STRING )
			return MPE_UNKNOWN;
		mp->map = 0;
		mp->crd = ll_copy_str(s->string.data);
		return 1;
	}
	else {
		for ( mp_ptr = 0 ; mp_ptr < ttl ; mp_ptr ++ ) {
set_cpu_msg(720020);
			reset_mp_entry(&mp[mp_ptr]);
			if ( get_type(s) != XLT_PAIR )
				break;
set_cpu_msg(720021);
			t = car(s);
			if ( get_type(t) != XLT_STRING )
				return MPE_UNKNOWN;
			mp[mp_ptr].map = ll_copy_str(t->string.data);
			s = cdr(s);
			t = car(s);
set_cpu_msg(720022);
			if ( get_type(t) != XLT_STRING ) {
				d_f_ree(mp[mp_ptr].map);
				mp[mp_ptr].map = 0;
				return MPE_UNKNOWN;
			}
			mp[mp_ptr].crd = ll_copy_str(t->string.data);
			s= cdr(s);
set_cpu_msg(720023);
		}
		return mp_ptr;
	}
}


void
rq_task3(TKEY d)
{
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
MP_T * n;
XL_SEXP * rrf_ret;

	que = (SYS_QUEUE *)GET_TKEY(d);
	key = touch_qkey(que);
	if ( key == 0 )
		return;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);


	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);
	for ( ; ; ) {

		gc_push(0,0,"routing_task");

		n = delete_queue(que,sq_key_cond,key,0);
		if ( n == 0 ) {
			gc_pop(0,0);
			break;
		}

set_cpu_msg(720013);
		if ( n->mp_ptr == 0 )
			n->remote = remote_routing_fast(ses,
				&n->mp_tbl[n->mp_ptr],
				n->ttl - n->mp_ptr,
				n->start,
				n->target_cid,
				n->mode,
				n->ret_mode,
				n->option);
		else	n->remote = remote_routing_fast(ses,
				&n->mp_tbl[n->mp_ptr],
				n->ttl - n->mp_ptr,
				n->mp_tbl[n->mp_ptr-1].crd,
				n->target_cid,
				n->mode,
				n->ret_mode,
				n->option);

		insert_queue_mp_t(&rque4,n,1);

		gc_pop(0,0);
	}

	release_qkey(que,key);
	d_f_ree(key);

	close_session(ses);
	close_self_interpreter();

}


int
rq_task4_cond(SYS_QUEUE * q,MP_T * n,L_CHAR * key)
{
int ret;
	if ( sq_key_cond(q,n,key) == -1 )
		return -1;
	ret = check_delay(n->remote,(int)q);

	if ( ret == CDT_WAIT )
		return -1;
	return 0;
}


void
rq_task4(TKEY d)
{
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
MP_T * n;
int ret;
int mp_ptr;

	que = (SYS_QUEUE *)GET_TKEY(d);
	key = touch_qkey(que);
	if ( key == 0 )
		return;

	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);

	ses = open_session(SEST_OPTIMIZE);


	xli = new_xl_interpreter();
	xli->a_type = XLA_SELF;
	setup_i(xli);
	for ( ; ; ) {

		gc_push(0,0,"routing_task");

set_cpu_msg(720041);
		if ( check_queue(que,sq_key_cond,key) == 0 ) {
			gc_pop(0,0);
			break;
		}
set_cpu_msg(720040);
		n = delete_queue(que,rq_task4_cond,key,1);

set_cpu_msg(720013);
		ret = remote_routing_result(
			n->remote,
			&n->mp_tbl[n->mp_ptr],
			n->ttl - n->mp_ptr,
			n);
set_cpu_msg(720014);
		if ( ret >= 0 ) {
			mp_ptr = n->mp_ptr;
			n->mp_ptr += ret;
			n->ret_sts = MPE_FIT;
set_cpu_msg(720015);
			routing_optimize(n,mp_ptr);
set_cpu_msg(720016);
		}
		else {
			n->ret_sts = ret;
		}
set_cpu_msg(720017);
		routing_result(n);
set_cpu_msg(720018);

		gc_pop(0,0);
	}
set_cpu_msg(720019);

	release_qkey(que,key);
	d_f_ree(key);

	close_session(ses);
	close_self_interpreter();

}



XL_SEXP *
gb_MPRouting(XLISP_ENV * env,XL_SEXP * s,
	XLISP_ENV * a,
	XL_SYM_FIELD * sf)
{
XL_SEXP * from;
XL_SEXP * target;
int ttl;
int mode,ret_mode;
int * _target;
MAP_PATH * mp, * mp1;
int i;
int ret,len;
XL_SEXP *ret_sexp;
int option;
MP_T * n;
URL u;

	for ( ; rque_init_flag == 0 ; )
		sleep_sec(1);


set_cpu_msg(720000);

	ttl = DEFAULT_TTL;
	mode = MPR_FAST;
	ret_mode = MPR_ROUTE;
	option = 0;
	for ( ; sf ; sf = sf->next ) {
		if ( l_strcmp(sf->name,l_string(std_cm,"ttl"))
				== 0 ) {
			ttl = atoi(n_string(std_cm,sf->data));
			if ( ttl > MAX_TTL )
				ttl = MAX_TTL;
		}
		else if ( l_strcmp(sf->name,l_string(std_cm,"mode"))
				== 0 ) {
			if ( l_strcmp(sf->data,l_string(std_cm,"best"))
					== 0 ) {
				mode = MPR_BEST;
			}
			else if ( l_strcmp(sf->data,l_string(std_cm,"fast"))
					== 0 ) {
				mode = MPR_FAST;
			}
			else	goto invalid_param;
		}
		else if ( l_strcmp(sf->name,l_string(std_cm,"return"))
				== 0 ) {
			if ( l_strcmp(sf->data,l_string(std_cm,"route"))
					== 0 ) {
				ret_mode = MPR_ROUTE;
			}
			else if ( l_strcmp(sf->data,l_string(std_cm,"target"))
					== 0 ) {
				ret_mode = MPR_TARGET;
			}
			else	goto invalid_param;
		}
		else if ( l_strcmp(sf->name,l_string(std_cm,"trigger"))
				== 0 ) {
			if ( l_strcmp(sf->data,l_string(std_cm,"on"))
					== 0 )
				option = 1;
			else 	option = 0;
		}
	}
set_cpu_msg(720001);
	from = get_el(s,1);
	switch ( get_type(from) ) {
	case XLT_STRING:
		break;
	defualt:
		goto type_missmatch;
	}
	target = get_el(s,2);

set_cpu_msg(721001);
	if ( mode == MPR_FAST ) {
		n = new_mp_t(ttl,from->string.data,0);
		n->mode = mode;
		n->ret_mode = ret_mode;
		n->option = option;
		n->ret_sts = 0;
		n->file = s->h.file;
		n->line = s->h.line;
set_cpu_msg(721002);
		switch ( get_type(target) ) {
		case XLT_STRING:
set_cpu_msg(721102);
			ret_sexp = new_d_sexp(&n->d);
			n->target = ll_copy_str(target->string.data);
			get_url2(&u,target->string.data);
			n->h.key = get_server_key(&u);
			free_url(&u);
			insert_queue_mp_t(&rque1,n,1);
			break;
		case XLT_PAIR:
set_cpu_msg(721003);
			n->target_cid = list2cid(target);
			if ( n->target_cid == 0 ) {
				free_mp_t(n);
				goto no_route;
			}
			ret_sexp = new_d_sexp(&n->d);
			n->h.key = nl_copy_str(std_cm,"*");
			insert_queue_mp_t(&rque2,n,1);
			break;
		default:
set_cpu_msg(721004);
			free_mp_t(n);
			goto type_missmatch;
		}
		return ret_sexp;
	}
set_cpu_msg(721005);

	switch ( get_type(target) ) {
	case XLT_STRING:
set_cpu_msg(721006);
		_target = url2cid(target->string.data);
		break;
	case XLT_PAIR:
set_cpu_msg(721007);
		_target = list2cid(target);
		break;
	default:
		goto type_missmatch;
	}
set_cpu_msg(721008);
	if ( _target == 0 )
		goto invalid_param2;
	mp = d_alloc(sizeof(MAP_PATH)*ttl);
set_cpu_msg(720002);
	reset_mp(mp,ttl);
	ret = MP_routing_over_site(&len,mp,ttl,
		from->string.data,_target,mode,ret_mode,option);
set_cpu_msg(720003);
	switch ( ret ) {
	case MPE_FIT:
set_cpu_msg(720004);
		if ( get_type(target) == XLT_STRING ) {
		URL u1,u2;
			get_url2(&u1,target->string.data);
			if ( len )
				get_url2(&u2,mp[len-1].crd);
			else 	get_url2(&u2,from->string.data);
			if ( url_cmp(&u1,&u2) ) {
				free_url(&u1);
				free_url(&u2);
				goto no_route;
			}
			free_url(&u1);
			free_url(&u2);
		}
		ret_sexp = get_fit_list(mp,len,ret_mode);
		break;
	case MPE_NO_ROUTE:
	no_route:
set_cpu_msg(720005);
		ret_sexp = get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_NO_ROUTE,
			l_string(std_cm,"MProuting"),
			n_get_string("there is no route of map path"));
		break;
	case MPE_OVER_TTL:
set_cpu_msg(720006);
		ret_sexp = get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_OVER_TTL,
			l_string(std_cm,"MProuting"),
			n_get_string("over time to live"));
		break;
	case MPE_UNKNOWN:
set_cpu_msg(720007);
		ret_sexp = get_error(
			s->h.file,
			s->h.line,
			XLE_PROTO_UNKNOWN,
			l_string(std_cm,"MProuting"),
			n_get_string("unknown error"));
		break;
	default:
		er_panic("MProuting");
	}
set_cpu_msg(720008);
	free_mp(mp,ttl);
	d_f_ree(_target);

set_cpu_msg(0);

	if ( get_type(ret_sexp) == XLT_ERROR ) {
		log_print_sexp(LOG_WARNING,"cmd",s,0);
		log_print_sexp(LOG_WARNING,"err",ret_sexp,0);
	} 

	return ret_sexp;

type_missmatch:

set_cpu_msg(0);

	return get_error(
		s->h.file,
		s->h.line,
		XLE_SEMANTICS_TYPE_MISSMATCH,
		l_string(std_cm,"MProuting"),
		n_get_string("type missmatch"));
invalid_param:

set_cpu_msg(0);

	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"MProuting"),
		n_get_string("invalid parameter (attribute)"));
invalid_param2:

set_cpu_msg(0);

	return get_error(
		s->h.file,
		s->h.line,
		XLE_PROTO_INV_PARAM,
		l_string(std_cm,"MProuting"),
		n_get_string("invalid target (type missmtch or not exist)"));

}

