/**********************************************************************
 
	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	"gbview.h"
#include	"avt.h"
#include	"task.h"
#include	"lock_level.h"
#include	"routing.h"
#include	"xl.h"
#include	"resource.h"
#include	"pri_level.h"
#include	"rt_cache.h"


#define MIN_CACHE_EXPIRE	60
#define MAX_CACHE_EXPIRE	(30*24*3600)
typedef struct rrr_type {
	struct rrr_type *	next;
	L_CHAR *		server;
	int			port;
	int			cnt;
} RRR_TYPE;

typedef struct purge_url {
	struct purge_url *	next;
	L_CHAR *		url;
} PURGE_URL;


MP_CACHE direct;
MP_CACHE indirect;

MP_ERR_ROUTE *	err_route_cache;

SEM route_lock;

PURGE_URL * purge_url_head, * purge_url_tail;

RRR_TYPE * rrr_list;

void _flush_route(MP_ROUTE *);
void err_route_tick();

SYS_QUEUE	rr_que1,rr_que2;
int cache_start;

MP_ROUTE_T * wait_list;

void rr_task_cache();

void
init_mp_cache(MP_CACHE * c)
{
int i;
MP_ROUTE * r;
	c->cache = d_alloc(sizeof(MP_ROUTE)*MP_ROUTE_CACHE_SIZE,22);
	memset(c->cache,0,sizeof(MP_ROUTE)*MP_ROUTE_CACHE_SIZE);
	c->root = &c->cache[0];
	c->root->next = c->root->prev = c->root;
	c->free_list = 0;
	for ( i = 1 ; i < MP_ROUTE_CACHE_SIZE ; i ++ ) {
		r = &c->cache[i];
		r->next = c->free_list;
		c->free_list = r;
	}
}

void
init_routing()
{
int i;
MP_ROUTE * r;
void rr_task1();
void rr_task2();

void gc_routing();
void gc_routing_get();
void gc_gb_sexp();

	route_lock = new_lock(LL_ROUTE_LOCK);
	init_mp_cache(&direct);
	init_mp_cache(&indirect);

	memset(&rr_que1,0,sizeof(SYS_QUEUE));
	rr_que1.flags = QF_STACK;
	rr_que1.gc_func = 0;
	rr_que1.gc_get = 0;
	rr_que1.key_func = rr_task1;
	rr_que1.pri = PRI_FETCH;
	setup_queue(&rr_que1);

	memset(&rr_que2,0,sizeof(SYS_QUEUE));
	rr_que2.flags = QF_STACK|QF_HIGH;
	rr_que2.gc_func = gc_routing;
	rr_que2.gc_get = gc_routing_get;
	rr_que2.key_func = rr_task2;
	rr_que2.pri = PRI_FETCH;
	setup_queue(&rr_que2);

	create_task(rr_task_cache,0,0);
	new_tick(err_route_tick,10,0);
}

void
gc_routing_get(MP_ROUTE_T * n)
{
void gc_gb_sexp();
	lock_mem();
	gc_set_nl(n->get,gc_gb_sexp);
	unlock_mem();
}


void
gc_routing(MP_ROUTE_T * n)
{
	gc_gb_sexp(n->get);
}

void
insert_rring(MP_CACHE * c,MP_ROUTE * r)
{
	r->prev = c->root;
	r->next = c->root->next;
	r->prev->next = r;
	r->next->prev = r;
}

void
delete_rring(MP_ROUTE * r)
{
	r->prev->next = r->next;
	r->next->prev = r->prev;
}


MP_ROUTE_T *
new_mp_route_t(L_CHAR * start,L_CHAR * target,int flags)
{
MP_ROUTE_T * n;
	n = new_queue_node(sizeof(*n),2346);
	n->start = ll_copy_str(start,346);
	n->target = ll_copy_str(target,346);
	n->flags = flags;
	n->route = 0;
	n->mh = 0;
	n->get = 0;
	return n;
}

void
_insert_purge_url(L_CHAR * url)
{
PURGE_URL * pm;
	pm = d_alloc(sizeof(*pm),22);
	pm->url = ll_copy_str(url,22);
	pm->next = 0;
	if ( purge_url_head ) {
		purge_url_tail->next = pm;
		purge_url_tail = pm;
	}
	else	purge_url_tail = purge_url_head = pm;
	cache_start = 1;
	wakeup_task((int)&cache_start);
}

void
insert_purge_url(L_CHAR * url)
{
	lock_task(route_lock);
	_insert_purge_url(url);
	unlock_task(route_lock,"insert_purge_url");
}

L_CHAR *
_delete_purge_url()
{
PURGE_URL * ret;
L_CHAR * _ret;
	if ( purge_url_head == 0 )
		return 0;
	ret = purge_url_head;
	purge_url_head = ret->next;
	if ( purge_url_head == 0 )
		purge_url_tail = 0;
	_ret = ret->url;
	d_f_ree(ret);
	return _ret;
}

L_CHAR *
delete_purge_url()
{
L_CHAR * ret;
	lock_task(route_lock);
	ret = _delete_purge_url();
	unlock_task(route_lock,"delete_purge_url");
	return ret;
}

void
free_mp_route_t(MP_ROUTE_T * n)
{
	if ( n->h.key )
		d_f_ree(n->h.key);
	d_f_ree(n->start);
	d_f_ree(n->target);
	d_f_ree(n);
}


void
_wait_mp_route(MP_ROUTE_T * n)
{
MP_ROUTE_T ** np;
MP_ROUTE * r;
	n->next = wait_list;
	wait_list = n;
	for ( ; ; ) {
		if ( n->route == 0 ) {
			if ( n->flags & RQT_ROUTE_RES_MASK )
				break;

/*
ss_printf("WAIT MP1 %ls -- %ls\n",n->start,n->target);
*/
			sleep_task((int)n,route_lock);
			lock_task(route_lock);
		}
		else if ( n->route->sts == RS_LOADING ) {

			r = n->route;
			r->lwait ++;
			sleep_task((int)r,route_lock);
			lock_task(route_lock);
			r->lwait --;
			wakeup_task((int)r);
		}
		else if ( n->flags & RQT_ROUTE_RES_MASK )
				break;
	}
/*
ss_printf("WAIT MP EX %ls -- %ls (%x)\n",n->start,n->target,n->flags);
if ( n->route )
ss_printf("LOCK %i %i\n",n->route->lock,n->route->sts);
*/

	for ( np = &wait_list ; *np ; np = &(*np)->next )
		if ( *np == n ) {
			*np = n->next;
			return;
		}
	er_panic("_wait_mp_route");
}

MP_ERR_ROUTE *
_search_err_route(L_CHAR * head,L_CHAR * tail)
{
L_CHAR * tmp;
MP_ERR_ROUTE * er;
	if ( l_strcmp(head,tail) > 0 ) {
		tmp = tail;
		tail = head;
		head = tmp;
	}
	for ( er = err_route_cache ; er ; er = er->next ) {
		if ( l_strcmp(er->head,head) )
			continue;
		if ( l_strcmp(er->tail,tail) )
			continue;
		return er;
	}
	return 0;
}

MP_ERR_ROUTE *
search_err_route(L_CHAR * head,L_CHAR * tail)
{
MP_ERR_ROUTE * ret;
	lock_task(route_lock);
	ret = _search_err_route(head,tail);
	unlock_task(route_lock,"search_err_route");
	return ret;
}

MP_ERR_ROUTE *
_new_err_route(L_CHAR * head,L_CHAR * tail)
{
L_CHAR * tmp;
MP_ERR_ROUTE * er;
	if ( l_strcmp(head,tail) > 0 ) {
		tmp = tail;
		tail = head;
		head = tmp;
	}
	for ( er = err_route_cache ; er ; er = er->next ) {
		if ( l_strcmp(er->head,head) )
			continue;
		if ( l_strcmp(er->tail,tail) )
			continue;
		return er;
	}
	er = d_alloc(sizeof(*er),124);
	er->head = ll_copy_str(head,115);
	er->tail = ll_copy_str(tail,124);
	er->next = err_route_cache;
	er->err_time = get_xltime();
	err_route_cache = er;
	return er;
}

MP_ERR_ROUTE *
new_err_route(L_CHAR * head,L_CHAR * tail)
{
MP_ERR_ROUTE * ret;
	lock_task(route_lock);
	ret = _new_err_route(head,tail);
	unlock_task(route_lock,"new_err_route");
	return ret;
}

void
err_route_tick()
{
unsigned int t;
MP_ERR_ROUTE ** erp, * er;
	t = get_xltime();
	lock_task(route_lock);
	for ( erp = &err_route_cache ; *erp ; ) {
		er = *erp;
		if ( t - er->err_time < ERR_ROUTE_TIMEOUT ) {
			erp = &er->next;
		}
		else {
			*erp = er->next;
			d_f_ree(er->head);
			d_f_ree(er->tail);
			d_f_ree(er);
		}
	}
	unlock_task(route_lock,"tick");
}



void
free_path(MP_ROUTE * r)
{
MP_PATH * p1,  * p2;
	if ( r->sts != RS_LOADING ) {
		p1 = r->head;
		for ( ; p1 ; ) {
			p2 = p1->next;
			d_f_ree(p1->url);
			d_f_ree(p1);
			p1 = p2;
		}
		r->head = r->tail = 0;
	}
	else {
		d_f_ree(r->head->url);
		d_f_ree(r->head);
		d_f_ree(r->tail->url);
		d_f_ree(r->tail);
		r->head = r->tail = 0;
	}
}

void
_delete_route(MP_CACHE * c,MP_ROUTE * r)
{
	if ( &c->cache[0] >= r )
		er_panic("_Delete_route(!)");
	if ( &c->cache[MP_ROUTE_CACHE_SIZE] <= r )
		er_panic("_delete_route(2)");
	delete_rring(r);
	free_path(r);
	r->next = c->free_list;
	c->free_list = r;
}


void
free_mp_path(MP_PATH * p)
{
MP_PATH * p2;
	for ( ; p ; ) {
		p2 = p->next;
		d_f_ree(p->url);
		d_f_ree(p);
		p = p2;
	}
}

void
free_copy_route(MP_ROUTE * r)
{
	free_mp_path(r->head);
	d_f_ree(r);
}



MP_ROUTE *
_copy_route(MP_ROUTE * r)
{
MP_PATH * from, * to;
MP_ROUTE * ret;
	ret = d_alloc(sizeof(*ret),22);
	*ret = *r;
	ret->head = ret->tail = 0;

	for ( from = r->head ; from ; from = from->next ) {
		to = d_alloc(sizeof(*to),3);
		*to = *from;
		to->url = ll_copy_str(from->url,22);
		to->next = 0;
		if ( ret->head ) {
			ret->tail->next = to;
			ret->tail = to;
		}
		else 	ret->head = ret->tail = to;
	}

	ret->next = ret->prev = 0;
	ret->sts = RS_COPY;
	ret->lock = 1;
	ret->lwait = 0;
	return ret;
}



MP_PATH *
copy_mp_path(MP_PATH * p)
{
MP_PATH * ret;
	ret = d_alloc(sizeof(*ret),22);
	ret->next = 0;
	ret->url = ll_copy_str(p->url,3);
	return ret;
}


MP_PATH *
sr_url(MP_PATH * path,L_CHAR * u)
{
MP_PATH * ret;
	for ( ret = path ; ret ; ret = ret->next )
		if ( l_strcmp(ret->url,u) == 0 )
			return ret;
	return 0;
}


MP_ROUTE *
_new_route(MP_CACHE * cc)
{
MP_ROUTE * r;
	if ( cc->free_list ) {
		r = cc->free_list;
		cc->free_list = r->next;
		insert_rring(cc,r);
		r->flags = 0;
		r->sts = 0;
		return r;
	}
	else {
		r = cc->root->prev;
		for ( ; r != cc->root && r->lock ; r = r->prev );
		if ( r == cc->root )
			er_panic("_new_route");
		free_path(r);
		insert_rring(cc,r);
		r->flags = 0;
		r->sts = 0;
		return r;
	}
}

MP_ROUTE *
_new_route2(MP_CACHE * cc,L_CHAR * start,L_CHAR * target)
{
MP_ROUTE * r;
MP_PATH * p1;
	r = _new_route(cc);
	r->head = p1 = d_alloc(sizeof(*p1),346);
	p1->url = ll_copy_str(start,235);
	p1->next = 0;
	r->tail = p1 = d_alloc(sizeof(*p1),346);
	p1->url = ll_copy_str(target,246);
	p1->next = 0;
	r->lock = 0;
	r->sts = RS_LOADING;
	return r;
}

MP_ROUTE *
_search_route(MP_CACHE * cc,L_CHAR * start,L_CHAR * target)
{
MP_ROUTE * inner;
MP_ROUTE * r;
MP_PATH * p, * p_start, * p_target, * p1, * p2;
int f;
	inner = 0;
	f = 0;
	for ( r = cc->root->next ; r != cc->root ; r = r->next ) {
		if ( r->head == 0 )
			continue;
		if ( l_strcmp(r->head->url,start) == 0 &&
				l_strcmp(r->tail->url,target) == 0 ) {
			delete_rring(r);
			insert_rring(cc,r);
			return r;
		}
		if ( inner )
			continue;
		f = 0;
		for ( p = r->head ; p ; p = p->next ) {
			if ( l_strcmp(p->url,start) == 0 ) {
				p_start = p;
				switch ( f ) {
				case 0:
					f = 1;
					break;
				case -1:
					f = -2;
					goto end;
				}
			}
			else if ( l_strcmp(p->url,target) == 0 ) {
				p_target = p;
				switch ( f ) {
				case 0:
					f = -1;
					break;
				case 1:
					f = 2;
					goto end;
				}
			}
		}
		continue;
	end:
		inner = r;
	}
	if ( inner == 0 )
		return 0;
	r = _new_route(cc);
	r->modify = inner->modify;
	r->update = inner->update;
	if ( f == 2 ) {
		r->head = r->tail = 0;
		for ( p1 = p_start ; ; p1 = p1->next ) {
			p = d_alloc(sizeof(*p),1);
			p->url = ll_copy_str(p1->url,1584);
			p->next = 0;
			if ( r->head == 0 )
				r->head = r->tail = p;
			else {
				r->tail->next = p;
				r->tail = p;
			}
			if ( p1 == p_target )
				break;
		}
	}
	else {
		r->head = r->tail = 0;
		for ( p1 = p_target ; ; p1 = p1->next ) {
			p = d_alloc(sizeof(*p),1);
			p->url = ll_copy_str(p1->url,1585);
			p->next = r->head;
			r->head = p;
			if ( r->tail == 0 )
				r->tail = p;
			if ( p1 == p_start )
				break;
		}
	}
	r->sts = RS_OK;
	return r;
}


void
_delete_route_cache(MP_CACHE * cc,L_CHAR * start,L_CHAR * target)
{
int cmp;
L_CHAR * tmp;
MP_ROUTE * mp;
	switch ( l_strcmp(start,target) ) {
	case -1:
		break;
	case 0:
		return;
	case 1:
		tmp = start;
		start = target;
		target = tmp;
	}
	for ( mp = cc->root->next ; mp != cc->root ; mp = mp->next ) {
		if ( mp->lock )
			continue;
		if ( l_strcmp(mp->head->url,start) == 0 &&
				l_strcmp(mp->tail->url,target) == 0 ) {
			_delete_route(cc,mp);
			return;
		}
	}
}

MP_PATH *
copy_mp_path_list(MP_PATH * p)
{
MP_PATH * ret,** retp,* path;
	ret = 0;
	retp = &ret;
	for ( ; p ; p = p->next ) {
		path = d_alloc(sizeof(*path),22);
		path->url = ll_copy_str(p->url,333);
		path->next = 0;
		*retp = path;
		retp = &path->next;
	}
	return ret;
}

int
cmp_mp_path(MP_PATH * a,MP_PATH * b)
{
int cmp;
	for ( ; a && b ; a = a->next , b = b->next ) {
		cmp = l_strcmp(a->url,b->url);
		if ( cmp == 0 )
			continue;
		return cmp;
	}
	if ( a )
		return 1;
	if ( b )
		return -1;
	return 0;
}

MP_ROUTE *
_insert_route(MP_ROUTE * r,XL_SEXP * list,L_CHAR * start,L_CHAR * target)
{
MP_PATH * p, * p1, * p2, * old;
XL_SEXP * rec;

	if ( r->sts == RS_OK )
		old = copy_mp_path_list(r->head);
	else	old = 0;
	free_path(r);
	p = 0;
	for ( ; get_type(list) == XLT_PAIR ; list = cdr(list) ) {
		rec = car(list);
		if ( get_type(rec) != XLT_STRING )
			goto err;
		p1 = d_alloc(sizeof(*p1),1245);
		p1->url = ll_copy_str(rec->string.data,1586);
		p1->next = p;
		p = p1;
	}
	if ( p == 0 )
		goto err;
	if ( l_strcmp(p->url,start) == 0 ) {
		for ( p1 = p ; p1->next ; p1 = p1->next );
		if ( l_strcmp(p1->url,target) )
			goto err;
	}
	else if ( l_strcmp(p->url,target) == 0 ) {
		p1 = 0;
		for ( ; p ; ) {
			p2 = p;
			p = p->next;
			p2->next = p1;
			p1 = p2;
		}
		p = p1;
		if ( l_strcmp(p->url,start) )
			goto err;
	}
	else	goto err;
	r->head = p;
	for ( ; p->next ; p = p->next );
	r->tail = p;
	r->update = get_xltime();
	if ( cmp_mp_path(old,r->head) == 0 ) {
		if ( r->modify == 0 )
			r->modify = r->update;
	}
	else	r->modify = r->update;
	r->sts = RS_OK;
	r->flags |= RF_DIRTY;
	free_mp_path(old);
	cache_start = 1;
	wakeup_task((int)&cache_start);
	return r;
err:
	r->sts = RS_ERR;
	r->update = get_xltime();
	if ( r->modify == 0 )
		r->modify = r->update;
	for ( ; p ; ) {
		p1 = p;
		p = p->next;
		d_f_ree(p1->url);
		d_f_ree(p1);
	}
	free_mp_path(old);
	return 0;
}


MP_PATH *
path_optimization(MP_PATH * path)
{
MP_PATH * p1, * p2, * p3;
	for ( p1 = path ; p1 ; p1 = p1->next ) {
		for ( p2 = p1->next ; p2 ; p2 = p2->next )
			if ( l_strcmp(p1->url,p2->url) == 0 )
				goto opt;
		continue;
	opt:
		p3 = p1->next;
		p1->next = p2->next;
		p2->next = 0;
		free_mp_path(p3);
	}
	return path;
}

MP_PATH *
_resolve_indirect_path(L_CHAR * start,L_CHAR * target)
{
MP_ROUTE * st, * tar;
MP_PATH * p_st,* p_tar;
MP_PATH * start_ptr, * target_ptr;
MP_PATH * p_st_result, * p, *pp, ** p_ptr;
MP_PATH * p_tar_result;
	for  ( st = direct.root->next ; st != direct.root ; st = st->next ) {
		if ( st->sts != RS_OK )
			continue;
		start_ptr = sr_url(st->head,start);
		if ( start_ptr == 0 )
			continue;
		for ( tar = direct.root->next ; tar != direct.root ;
				tar = tar->next ) {
			if ( tar->sts != RS_OK )
				continue;
			target_ptr = sr_url(tar->head,target);
			if ( target_ptr == 0 )
				continue;
			for ( p_tar = tar->head ; p_tar ;
					p_tar = p_tar->next ) {
				p_st = sr_url(st->head,p_tar->url);
				if ( p_st )
					goto ok;
			}
		}
	}
	return 0;
ok:
	p_st_result = 0;
	for ( p = p_st ; p ; p = p->next ) {
		pp = copy_mp_path(p);
		pp->next = p_st_result;
		p_st_result = pp;
		if ( p == start_ptr )
			break;
	}
	if ( p == 0 ) {
		free_mp_path(p_st_result);
		p_st_result = 0;
		p_ptr = &p_st_result;
		for ( p = start_ptr ; ; p = p->next ) {
			pp = copy_mp_path(p);
			*p_ptr = pp;
			p_ptr = &pp->next;
			if ( p == p_st )
				break;
		}
	}
	p_tar_result = 0;
	for ( p = target_ptr ; p && p != p_tar ; p = p->next ) {
		pp = copy_mp_path(p);
		pp->next = p_tar_result;
	}
	if ( p == 0 ) {
		free_mp_path(p_tar_result);
		p_tar_result = 0;
		p_ptr = &p_tar_result;
		for ( p = p_tar->next ; ; p = p->next ) {
			pp = copy_mp_path(p);
			*p_ptr = pp;
			p_ptr = &pp->next;
			if ( p == target_ptr )
				break;
		}
	}
	for ( p = p_st_result ; p->next ; p = p->next );
	p->next = p_tar_result;
	return path_optimization(p_st_result);
}

MP_ROUTE *
_resolve_direct(L_CHAR * start,L_CHAR * target)
{
int cmp;
MP_ROUTE *ret;
	cmp = l_strcmp(start,target);
	switch ( cmp ) {
	case -1:
		ret = _search_route(&direct,start,target);
		break;
	case 0:
		return 0;
	case 1:
		ret = _search_route(&direct,target,start);
		break;
	default:
		er_panic("resolve_direct");
	}
	if ( ret == 0 )
		return MP_NO_ROUTE;
	ret->lock ++;
	return ret;
}

MP_ROUTE *
_resolve_indirect(int * sts,L_CHAR * start,L_CHAR * target)
{
int cmp;
MP_ROUTE * ret;
MP_PATH * path, * p;
int _sts;
	cmp = l_strcmp(start,target);
	switch ( cmp ) {
	case -1:
		_sts = RI_UNRESOLVE;
		ret = _search_route(&direct,start,target);
		if ( ret ) {
			switch ( ret->sts ) {
			case RS_OK:
				*sts = RI_DIRECT;
				ret->lock ++;
				return ret;
			case RS_ERR:
				_sts = RI_ERR;
				break;
			case RS_LOADING:
				_sts = RI_LOADING;
				break;
			default:
				_sts = RI_ERR;
			}
		}
		ret = _search_route(&indirect,start,target);
		if ( ret ) {
			*sts = RI_INDIRECT;
			ret->lock ++;
			return ret;
		}
		path = _resolve_indirect_path(start,target);
		if ( path == 0 ) {
			*sts = _sts;
			return MP_NO_ROUTE;
		}
		break;
	case 0:
		*sts = RI_DIRECT;
		return 0;
	case 1:
		_sts = RI_UNRESOLVE;
		ret = _search_route(&direct,target,start);
		if ( ret ) {
			switch ( ret->sts ) {
			case RS_OK:
				*sts = RI_DIRECT;
				ret->lock ++;
				return ret;
			case RS_ERR:
				_sts = RI_ERR;
				break;
			case RS_LOADING:
				_sts = RI_LOADING;
				break;
			default:
				_sts = RI_ERR;
			}
		}
		ret = _search_route(&indirect,target,start);
		if ( ret ) {
			*sts = RI_INDIRECT;
			ret->lock ++;
			return ret;
		}
		path = _resolve_indirect_path(target,start);
		if ( path == 0 ) {
			*sts = _sts;
			return MP_NO_ROUTE;
		}
		break;
	}
	ret = _new_route(&indirect);
	ret->head = path;
	for ( p = path ; p->next ; p = p->next );
	ret->tail = p;
	ret->lock = 1;
	ret->lwait = 0;
	ret->sts = RS_OK;
	*sts = RI_INDIRECT;
	ret->lock ++;
	return ret;
}


MP_ROUTE *
_get_in_file(L_CHAR * start,L_CHAR * target)
{
MP_ROUTE * ret,* new_r;

	unlock_task(route_lock,"_get_in_file");
	ret = get_rt_cache(start,target);
printf("GET RT %x\n",ret);
	lock_task(route_lock);
	if ( ret == 0 )
		return 0;
	new_r = _new_route(&direct);
	new_r->head = ret->head;
	new_r->tail = ret->tail;
	new_r->modify = ret->modify;
	new_r->update = ret->update;
	new_r->sts = RS_OK;
	d_f_ree(ret);
	return new_r;
}


MP_ROUTE *
_resolve_in_file(MP_ROUTE ** org,L_CHAR * start,L_CHAR * target)
{
MP_ROUTE * ret, * new_r;
int cmp;
	cmp = l_strcmp(start,target);
	switch ( cmp ) {
	case -1:
		*org = _get_in_file(start,target);
		if ( *org == 0 ) {
			ret = 0;
			break;
		}
		(*org)->lock ++;
		ret = _search_route(&direct,start,target);
		if ( ret == 0 )
			ret = 0;
		else	ret->lock ++;
		break;
	case 0:
		ret = 0;
		break;
	case 1:
		*org = _get_in_file(target,start);
		if ( *org == 0 ) {
			ret = 0;
			break;
		}
		(*org)->lock ++;
		ret = _search_route(&direct,target,start);
		if ( ret == 0 )
			ret = 0;
		else	ret->lock ++;
		break;
	}
	return ret;
}

RRR_TYPE *
_rrr_search(URL * u)
{
RRR_TYPE * r;
RRR_TYPE * ret;
	ret = 0;
	for ( r = rrr_list ; r ; r = r->next )
		if ( l_strcmp(r->server,u->server) == 0 &&
				r->port == u->port ) {
			ret = r;
			break;
		}

	return ret;
}

int
rrr_check(L_CHAR * st)
{
int ret;
URL u;
	get_url2(&u,st,111);
	lock_task(route_lock);
	if ( _rrr_search(&u) )
		ret = 1;
	else	ret = 0;
	unlock_task(route_lock,"rrr_check");
	free_url(&u);
	return ret;
}

void
rrr_insert(L_CHAR * st)
{
URL u;
RRR_TYPE * r;
	get_url2(&u,st,112);
	lock_task(route_lock);
	r = _rrr_search(&u);
	if ( r == 0 ) {
		r = d_alloc(sizeof(*r),111);
		r->server = ll_copy_str(u.server,115);
		r->port = u.port;
		r->cnt = 1;
		r->next = rrr_list;
		rrr_list = r;
	}
	else {
		r->cnt ++;
	}
	unlock_task(route_lock,"rrr_insert");
	free_url(&u);
}

void
rrr_delete(L_CHAR * st)
{
URL u;
RRR_TYPE * r, ** rp;
	get_url2(&u,st,113);
	lock_task(route_lock);
	r = _rrr_search(&u);
	if ( r == 0 )
		er_panic("rrr_Delete");
	r->cnt --;
	if ( r->cnt == 0 ) {
		for ( rp = &rrr_list ; *rp ; rp = &(*rp)->next )
			if ( r == *rp )
				break;
		if ( *rp == 0 )
			er_panic("rrr_delete(2)");
		*rp = r->next;
		d_f_ree(r->server);
		d_f_ree(r);
	}
	unlock_task(route_lock,"rrr_delete");
}


L_CHAR * 
get_body(L_CHAR * url)
{
URL u;
RESOURCE * r;
	get_url2(&u,url,346);
	r = search_resource_by_entry(&u);
	if ( r == 0 )
		return 0;
	if ( r->h.type != RT_COORDINATE )
		return 0;
	return r->c.body_pri;
}

void
_resolve_route(MP_ROUTE_T * n)
{
int cmp;
MP_ROUTE * r;
XL_SEXP * list;
L_CHAR * b_start, * b_target;
L_CHAR * tmp;

	if ( search_err_route(n->start,n->target) ) {
		n->flags |= RQT_ROUTE_ERR;
		return;
	}
	b_start = get_body(n->start);
	b_target = get_body(n->target);
	if ( b_start && b_target && l_strcmp(b_start,b_target) ) {
ss_printf("RESOLVE_ERROR %ls %ls\n",n->start,n->target);
		n->flags |= RQT_ROUTE_ERR;
		return;
	}
	cmp = l_strcmp(n->start,n->target);
	switch ( cmp ) {
	case 0:
		n->flags |= RQT_ROUTE_OK;
		wakeup_task((int)n);
		break;
	case -1:
		n->handle1_start = n->start;
		n->handle1_target = n->target;
		lock_task(route_lock);
		n->route = _search_route(&direct,n->start,n->target);
		if ( n->route ) {
			n->route->lock ++;
			n->flags |= RQT_ROUTE_OK;
		}
		unlock_task(route_lock,"resolve_route");
		break;
	case 1:
		n->handle1_start = n->target;
		n->handle1_target = n->start;
		lock_task(route_lock);
		n->route = _search_route(&direct,
				n->handle1_start,n->handle1_target);
		if ( n->route ) {
			n->route->lock ++;
			n->flags |= RQT_ROUTE_OK;
		}
		unlock_task(route_lock,"resolve_route");
		break;
	}
	if ( (n->flags & RQT_ROUTE_RES_MASK)== 0 ) {
	URL u;
		if ( rrr_check(n->start) &&
				rrr_check(n->target) == 0 ) {
			n->handle2_start = n->target;
			n->handle2_target = n->start;
		}
		else {
			n->handle2_start = n->start;
			n->handle2_target = n->target;
		}
		get_url2(&u,n->handle2_start,346);
		n->h.key = get_server_key(&u);
		free_url(&u);
		insert_queue(&rr_que1,n,1);
	}
	else {
		if ( (n->flags & RQT_LOCK_MASK) == RQT_UNLOCK ) {
			if ( n->route )
				flush_route(n->route);
			free_mp_route_t(n);
		}
	}
	return;
}

void
rr_task1(TKEY d)
{
MP_ROUTE_T * n;
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
int ses;
XL_SEXP * cmd;
URL u;
unsigned int now;
int diff;
MP_ROUTE * r1, * r2;

	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);


	for ( ; ; ) {

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

		lock_task(route_lock);
		n->route = r1
			= _resolve_in_file(&r2,n->handle1_start,n->handle1_target);

		if ( n->route ) {
			n->flags |= RQT_ROUTE_OK;
			wakeup_task((int)n->route);
			wakeup_task((int)n);
			if ( (n->flags & RQT_LOCK_MASK) == RQT_UNLOCK ) {
				if ( n->route )
					_flush_route(n->route);
				free_mp_route_t(n);
			}
			now = get_xltime();
			diff = r2->update - r2->modify;
			if ( diff < MIN_CACHE_EXPIRE )
				diff = MIN_CACHE_EXPIRE;
			else if ( diff > MAX_CACHE_EXPIRE )
				diff = MAX_CACHE_EXPIRE;
			if ( r2->update + diff < now ) {
				n = new_mp_route_t(
					r2->head->url,
					r2->tail->url,
					RQT_UNLOCK|RQT_ROUTE);
				n->route = r2;
				n->handle1_start = n->start;
				n->handle1_target = n->target;
				n->handle2_start = n->start;
				n->handle2_target = n->target;
			}
			else {
				/* cache is usable */
				unlock_task(route_lock,"rr_task1");
				continue;
			}
		}
		else {
			n->route = 
				_new_route2(
					&direct,
					n->handle1_start,
					n->handle1_target);
			n->route->lock = 1;
			wakeup_task((int)n);
		}
		unlock_task(route_lock,"resolve_route");

		rrr_insert(n->handle2_start);

		gc_push(0,0,"rr_task1");

		cmd = n_get_symbol("MPRouting");
		if ( n->flags & RQT_ROUTE_REVERSE )
			set_attribute(cmd,
				l_string(std_cm,"trigger"),
				l_string(std_cm,"on"));
		get_url2(&u,n->handle2_start,1612);

		n->get = remote_session(
			gblisp_top_env0,
			ses,
			&u,
			l_string(std_cm,"gbstd"),
			l_string(std_cm,"user"),
			l_string(std_cm,"Get"),
			List(
				List(cmd,
					get_string(n->handle2_start),
					get_string(n->handle2_target),
					-1),
				-1),
			0,0,0);
		free_url(&u);

		insert_queue(&rr_que2,n,1);

		gc_pop(0,0);

	}

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

	close_session(ses);
	close_self_interpreter();

}

int
rr_task2_cond(SYS_QUEUE * q,MP_ROUTE_T * n,L_CHAR * key)
{
int ret;
	if ( sq_key_cond(q,n,key) == -1 )
		return -1;
	ret = check_delay(n->get,(int)q);
/*
ss_printf("C %ls %i\n",key,ret);
*/
	if ( ret == CDT_WAIT )
		return -1;
	return 0;
}



void
rr_task2(TKEY d)
{
MP_ROUTE_T * n;
SYS_QUEUE * que;
L_CHAR * key;
XL_INTERPRETER * xli;
XL_SEXP * cmd;
URL u;
L_CHAR * tmp;
MP_ROUTE * r;
int flags;


	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);


	for ( ; ; ) {
		gc_push(0,0,"rr_task1");

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


		rrr_delete(n->handle2_start);


		if ( get_type(n->get) != XLT_ERROR ) {
			n->get = cons(get_string(n->handle2_start),n->get);

			lock_task(route_lock);
			if ( _insert_route(
					n->route,
					n->get,
					n->handle1_start,
					n->handle1_target) == 0 )
				goto err;
			_delete_route_cache(&indirect,
				n->handle1_start,
				n->handle1_target);
			flags = n->flags;
			n->flags |= RQT_ROUTE_OK;
			wakeup_task((int)n->route);

			wakeup_task((int)n);

			gc_pop(0,0);

			goto last;
		}
		lock_task(route_lock);
		if ( n->flags & RQT_ROUTE_REVERSE ){
			_new_err_route(n->handle1_start,n->handle1_target);

ss_printf("ERR %ls %ls\n",n->handle1_start,n->handle1_target);
			goto err;
		}
ss_printf("ERR RETRY %ls %ls\n",n->handle1_start,n->handle1_target);
		n->flags |= RQT_ROUTE_REVERSE;
		unlock_task(route_lock,"rr_task2");

		tmp = n->handle2_target;
		n->handle2_target = n->handle2_start;
		n->handle2_start = tmp;
		if ( n->h.key )
			d_f_ree(n->h.key);
		get_url2(&u,n->handle2_start,346);
		n->h.key = get_server_key(&u);
		free_url(&u);

		insert_queue(&rr_que1,n,1);

		gc_pop(0,0);
		continue;

	err:
		flags = n->flags;
		n->flags |= RQT_ROUTE_ERR;
		r = n->route;
		n->route = 0;
		r->sts = RS_ERR;

		for ( ; r->lwait ; ) {
			wakeup_task((int)r);
			sleep_task((int)r,route_lock);
			lock_task(route_lock);
		}
		_delete_route(&direct,r);
		gc_pop(0,0);

	last:
		if ( (flags & RQT_LOCK_MASK) == RQT_UNLOCK ) {
			if ( n->route )
				_flush_route(n->route);
			free_mp_route_t(n);
		}
		unlock_task(route_lock,"rr_task");
	}
	release_qkey(que,key);
	d_f_ree(key);

	close_self_interpreter();

}

typedef struct mp_list {
	struct mp_list *	next;
	MP_ROUTE *		mp;
} MP_LIST;

void
rr_task_cache()
{
MP_ROUTE * mp;
int f;
MP_LIST * lst, * el;
L_CHAR * map;
	for ( ; ; ) {
		lock_task(route_lock);
		for ( ; cache_start == 0 ; ) {
			sleep_task((int)&cache_start,route_lock);
			lock_task(route_lock);
		}
		cache_start = 0;
		lst = 0;
		for ( mp = direct.root->next ;
				mp != direct.root ;
				mp = mp->next ) {
			if ( mp->sts != RS_OK )
				continue;
			if ( !(mp->flags & RF_DIRTY) )
				continue;
			mp->flags &= ~RF_DIRTY;
			el = d_alloc(sizeof(*el),22);
			el->mp = mp;
			el->next = lst;	
			lst = el;
			mp->lock ++;
		}
		unlock_task(route_lock,"rr_task_cache");

		for ( ; lst ; ) {
			el = lst;
printf("SET RT %ls %ls\n",el->mp->head->url,el->mp->tail->url);
			set_rt_cache(el->mp);

			flush_route(el->mp);
		
			lst = el->next;
			d_f_ree(el);
		}
		flush_rt_cache();

		sleep_sec(1);

		for ( ; ; ) {
			map = delete_purge_url();
			if ( map == 0 )
				break;
			purge_rcache(map);
			d_f_ree(map);
		}
		flush_rt_cache();
	}
}

MP_ROUTE *
resolve_route(L_CHAR * start,L_CHAR * target,int wait_flag)
{
MP_ROUTE_T * n;
int type;
MP_ROUTE * ret, * _ret;
int sts;


	ret = 0;
	lock_task(route_lock);
	switch ( wait_flag ) {
	case RR_WM_NO_WAIT:
	case RR_WM_DIRECT:
		break;
	case RR_WM_DIRECT_NO_WAIT:
		ret = _resolve_direct(start,target);
		if ( ret && ret != MP_NO_ROUTE ) {
			switch ( ret->sts ) {
			case RS_LOADING:
				ret = MP_NO_ROUTE;
				break;
			case RS_OK:
				break;
			case RS_ERR:
				wait_flag = RR_WM_INDIRECT_NO_WAIT;
				goto indirect_pos;
			default:
				er_panic("resolve_route");
			}
		}
		wait_flag = RR_WM_NO_WAIT;
		break;
	case RR_WM_INDIRECT:
	case RR_WM_INDIRECT_NO_WAIT:
	indirect_pos:
		ret = _resolve_indirect(&sts,start,target);
		switch ( sts ) {
		case RI_INDIRECT:
		case RI_DIRECT:
		case RI_ERR:
			wait_flag = RR_WM_NO_WAIT;
			break;
		case RI_LOADING:
		case RI_UNRESOLVE:
			if ( wait_flag == RR_WM_INDIRECT )
				wait_flag = RR_WM_DIRECT;
			else	wait_flag = RR_WM_NO_WAIT;
			break;
		default:
			er_panic("resolve_route");
		}
		break;
	default:
		er_panic("resolve_route");
	}
	unlock_task(route_lock,"resolve_route");

	if ( wait_flag != RR_WM_NO_WAIT )
		type = RQT_LOCK|RQT_ROUTE;
	else	type = RQT_ROUTE;
	n = new_mp_route_t(start,target,type);
	_resolve_route(n);

	lock_task(route_lock);
	if ( wait_flag == RR_WM_NO_WAIT ) {
		goto end;
	}
	_wait_mp_route(n);

ss_printf("STS %x %x\n",n,n->flags);

	if ( (n->flags & RQT_ROUTE_RES_MASK) == RQT_ROUTE_ERR )
		ret = MP_NO_ROUTE;
	else	ret = n->route;
	if ( (n->flags & RQT_LOCK_MASK) == RQT_LOCK )
		free_mp_route_t(n);
end:
	if ( ret == MP_NO_ROUTE )
		_ret = MP_NO_ROUTE;
	else if ( ret ) {
		_ret = _copy_route(ret);
		_flush_route(ret);
	}
	else	_ret = 0;
	unlock_task(route_lock,"resolve_route");

	return _ret;
}

void
_flush_route(MP_ROUTE * r)
{
	if ( r == 0 )
		return;
	if ( r == MP_NO_ROUTE )
		return;
	if ( r->lock == 0 )
		er_panic("flush_route");
	if ( r->lock > 0 )
		r->lock --;
	if ( r->lock == 0 && r->sts == RS_COPY )
		free_copy_route(r);
}

void
flush_route(MP_ROUTE * r)
{
	lock_task(route_lock);
	_flush_route(r);
	unlock_task(route_lock,"flush_route");
}


int
path_length(MP_PATH * p)
{
int ret;
	for ( ret = 0 ; p ; p = p->next, ret ++ );
	return ret;
}

void
print_mpr(MP_ROUTE * mpr)
{
MP_PATH * c;
	printf("mpr\n");
	for ( c = mpr->head ; c ; c = c->next )
		printf("\t%s\n",n_string(std_cm,c->url));
	printf("mpr end\n");
}



int
check_mh_from_route(URL * u,MP_ROUTE * mpr,int loading_flag)
{
MP_PATH * crd_prev, * map, * crd_next;
URL uu;
RESOURCE * r;
int len;
int ret;

LOAD_RESOURCE_WORK * w, * wp;


set_t_msg(2000);

	w = 0;
	ret = CRT_EXIST;
	for ( crd_prev = mpr->head ; ;
			crd_prev = crd_next ) {
		if ( crd_prev == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(5)");
		}

		map = crd_prev->next;
		if ( map == 0 )
			break;
		crd_next = map->next;
		if ( crd_next == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(4)");
		}
		len = l_strlen(crd_prev->url);
		if ( l_strcmp(&crd_prev->url[len-4],
				l_string(std_cm,".crd")) ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route");
		}
		if ( resource_check(crd_prev->url,LRO_UNIT) == 0 )
			continue;
		ret = CRT_LOADING_RES;
		if ( loading_flag ) {
			w = new_lrw(w);
			get_url2(&w->url,crd_prev->url,1614);
			w->option = LRO_UNIT;
			w->err = LRWE_HANDLING;
		}
	}

set_t_msg(2001);

	for ( crd_prev = mpr->head ; ;
			crd_prev = crd_next ) {
		if ( crd_prev == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(5)");
		}

		map = crd_prev->next;
		if ( map == 0 )
			break;
		crd_next = map->next;
		if ( crd_next == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(4)");
		}
		len = l_strlen(map->url);
		if ( l_strcmp(&map->url[len-4],l_string(std_cm,".map")) ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route");
		}
		if ( resource_check(map->url,0) == 0 )
			continue;
		ret = CRT_LOADING_RES;
		if ( loading_flag ) {
			w = new_lrw(w);
			get_url2(&w->url,map->url,1614);
			w->err = LRWE_HANDLING;
		}
	}
	if ( loading_flag ) {
		if ( w )
		load_resource_list(w,Q_PRI_ROUTING,0);
		return ret;
	}
	else {
		return ret;
	}
}

MAP_HISTORY *
get_mh_from_route(int ses,URL * u,MP_ROUTE * mpr)
{
MP_PATH * crd_prev, * map, * crd_next;
MAP_HISTORY * ret, * ret1;
URL uu;
RESOURCE * r;
int len;
int err_flag;

LOAD_RESOURCE_WORK * w, * wp;


set_cpu_msg(2000);

	w = 0;
	for ( crd_prev = mpr->head ; ;
			crd_prev = crd_next ) {
		if ( crd_prev == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(5)");
		}

		map = crd_prev->next;
		if ( map == 0 )
			break;
		crd_next = map->next;
		if ( crd_next == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(4)");
		}
		len = l_strlen(crd_prev->url);
		if ( l_strcmp(&crd_prev->url[len-4],
				l_string(std_cm,".crd")) ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route");
		}
		w = new_lrw(w);
		get_url2(&w->url,crd_prev->url,1614);
		w->option = LRO_UNIT;
		w->err = LRWE_HANDLING;
	}

set_cpu_msg(2001);

	for ( crd_prev = mpr->head ; ;
			crd_prev = crd_next ) {
		if ( crd_prev == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(5)");
		}

		map = crd_prev->next;
		if ( map == 0 )
			break;
		crd_next = map->next;
		if ( crd_next == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(4)");
		}
		len = l_strlen(map->url);
		if ( l_strcmp(&map->url[len-4],l_string(std_cm,".map")) ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route");
		}
		w = new_lrw(w);
		get_url2(&w->url,map->url,1614);
		w->err = LRWE_HANDLING;
	}
set_cpu_msg(2002);
	load_resource_list(w,Q_PRI_ROUTING,1);
set_cpu_msg(2003);

	ret = 0;
	wp = w;
	err_flag = 0;
	for ( crd_prev = mpr->head ; ;
			crd_prev = crd_next ) {
		if ( crd_prev == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(2)");
		}

		map = crd_prev->next;
		if ( map == 0 )
			break;
		crd_next = map->next;
		if ( crd_next == 0 ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route(1)");
		}
		len = l_strlen(map->url);
		if ( l_strcmp(&map->url[len-4],l_string(std_cm,".map")) ) {
			print_mpr(mpr);
			er_panic("get_mh_from_route");
		}
		get_url2(&uu,map->url,1614);
		r = get_lrw(w,&uu);
		free_url(&uu);
		if ( r == 0 ) {
			err_flag = 1;
			insert_purge_url(map->url);
			goto nx1;
		}
		get_url2(&uu,crd_prev->url,1615);
		if ( url_cmp(&uu,&r->map.src) == 0 ) {
			get_url2(&uu,crd_next->url,122);
			if ( url_cmp(&uu,&r->map.dest) ) {
				err_flag = 1;
				insert_purge_url(map->url);
				goto nx1;
			}
			ret = cons_mh(r,MHD_REVERSE,ret);
		}
		else {
			if ( url_cmp(&uu,&r->map.dest) ) {
				err_flag = 1;
				insert_purge_url(map->url);
				goto nx1;
			}
			get_url2(&uu,crd_next->url,222);
			if ( url_cmp(&uu,&r->map.src) ) {
				err_flag = 1;
				insert_purge_url(map->url);
				goto nx1;
			}
			ret = cons_mh(r,MHD_FORWARD,ret);
		}
	nx1:
		free_url(&uu);
	}
	if ( err_flag )
		goto err;

set_cpu_msg(2004);
	free_lrw_req_next(w);
set_cpu_msg(2005);

	get_url2(&uu,mpr->head->url,1617);
	if ( url_cmp(&uu,u) == 0 ) {
		ret1 = rev_mh(ret);
		free_mh(ret);
		ret = ret1;
	}
set_cpu_msg(2006);
	free_url(&uu);
set_cpu_msg(2007);

	return ret;
err:

set_cpu_msg(2008);
	free_mh(ret);

	return MP_MH_NO_ROUTE;
}


MAP_HISTORY *
resolve_mappath(int ses,L_CHAR * org,L_CHAR * target,int wait_mode)
{
MP_ROUTE * mpr;
URL u;
MAP_HISTORY * mh;


	mpr = resolve_route(org,target,wait_mode);
	if ( mpr == MP_NO_ROUTE )
		return MP_MH_NO_ROUTE;
	if ( mpr == 0 )
		return 0;
	get_url2(&u,org,1618);
	mh = get_mh_from_route(ses,&u,mpr);
	free_url(&u);
	flush_route(mpr);
	return mh;
}


int
check_routing_table(L_CHAR * start,L_CHAR * target)
{

L_CHAR * b_start, * b_target;
int cmp;
MP_ROUTE * r;
int ret;
int sts;

	if ( search_err_route(start,target) )
		return CRT_ERROR;
	b_start = get_body(start);
	b_target = get_body(target);
	if ( b_start && b_target && l_strcmp(b_start,b_target) )
		return CRT_ERROR;
/*
	cmp = l_strcmp(start,target);
	if ( cmp == 0 )
		return CRT_EXIST;
*/
	lock_task(route_lock);
/*
	switch ( cmp ) {
	case -1:
		r = _search_route(&direct,start,target);
		break;
	case 1:
		r = _search_route(&direct,target,start);
		break;
	}
	if ( r == 0 ) {
		ret = CRT_NOTHING;
	}
	else switch ( r->sts ) {
	case RS_OK:
		ret = CRT_EXIST;
		break;
	case RS_LOADING:
		ret = CRT_LOADING;
		break;
	default:
		ret = CRT_ERROR;
	}
*/
	r = _resolve_indirect(&sts,start,target);
	switch ( sts ) {
	case RI_DIRECT:
		ret = CRT_EXIST;
		break;
	case RI_INDIRECT:
		ret = CRT_EXIST;
		break;
	case RI_LOADING:
		ret = CRT_LOADING;
		break;
	case RI_UNRESOLVE:
		ret = CRT_NOTHING;
		break;
	case RI_ERR:
		ret = CRT_ERROR;
		break;
	}
	_flush_route(r);
	unlock_task(route_lock,"check_routing_table");
	return ret;
}

int
check_mappath(L_CHAR * org,L_CHAR * target,int loading_flag)
{
MP_ROUTE * mpr;
URL u;
MAP_HISTORY * mh;
int ret;
int ret_cnt;

	ret_cnt = 3;
retry:
	ret = check_routing_table(org,target);
	if ( ret != CRT_EXIST )
		return ret;

	mpr = resolve_route(org,target,RR_WM_INDIRECT);
	if ( mpr == MP_NO_ROUTE ) {
		ret_cnt --;
		if ( ret_cnt <= 0 )
			er_panic("check_mappath");
		goto retry;
	}
	if ( mpr == 0 )
		return CRT_EXIST;
	get_url2(&u,org,1618);
	ret = check_mh_from_route(&u,mpr,loading_flag);
	free_url(&u);
	flush_route(mpr);
	return ret;
}

