|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 39321 (0x9999)
Types: TextFile
Names: »dsa_chain.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0
└─⟦35176feda⟧ »EurOpenD22/isode/isode-6.tar.Z«
└─⟦de7628f85⟧
└─⟦this⟧ »isode-6.0/quipu/dsa_chain.c«
/* dsa_chain.c - take referral and chain if allowed */
#ifndef lint
static char *rcsid = "$Header: /f/osi/quipu/RCS/dsa_chain.c,v 7.2 89/12/19 16:20:26 mrose Exp $";
#endif
/*
* $Header: /f/osi/quipu/RCS/dsa_chain.c,v 7.2 89/12/19 16:20:26 mrose Exp $
*
*
* $Log: dsa_chain.c,v $
* Revision 7.2 89/12/19 16:20:26 mrose
* sync
*
* Revision 7.1 89/11/27 10:30:12 mrose
* sync
*
* Revision 7.0 89/11/23 22:17:21 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
#include "acsap.h"
#include "quipu/util.h"
#include "quipu/connection.h"
extern LLog * log_dsap;
extern int dn_print ();
extern char * mydsaname;
extern DN mydsadn;
extern int no_dsp_chain;
struct oper_act * task2oper();
struct di_block * di_alloc();
struct di_block * select_refer_dsa();
Conn conn_alloc();
struct oper_act * oper_alloc();
struct PSAPaddr * psap_cpy();
struct access_point *ap_cpy ();
Conn make_conn_block(name, addr, conn_ctx)
DN name;
struct PSAPaddr * addr;
char conn_ctx;
{
Conn cn;
/*
* Set up a new connection block and add it to the list.
*/
(void) dn_decode (name);
if(dn_cmp(name, mydsadn) == 0)
{
LLOG(log_dsap, LLOG_FATAL, ("Trying to connect to self :-)"));
return(NULLCONN);
}
if((cn = conn_alloc()) == NULLCONN)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("make_conn_block - conn_alloc() out of memory"));
return(NULLCONN);
}
cn->cn_state = CN_WAITING;
cn->cn_ctx = conn_ctx;
cn->cn_initiator = INITIATED_BY_THIS;
make_dsa_bind_arg(&(cn->cn_init_act.ia_req));
cn->cn_what = dn_cpy(name);
DLOG (log_dsap,LLOG_TRACE,( "Before psap_dup: %s", paddr2str(addr,NULLNA)));
psap_dup(&(cn->cn_addr), addr);
DLOG (log_dsap,LLOG_TRACE,( "After psap_dup: %s", paddr2str(&(cn->cn_addr),NULLNA)));
return(cn);
}
int link_op_to_conn(on)
struct oper_act * on;
{
char conn_ctx = CN_CTX_X500_DSP;
struct di_block * di;
struct di_block **next_di;
struct connection * cn;
int do_conn;
struct access_point * loop_ap;
int res;
sort_dsa_list (&on->on_dsas);
/*
* Use an open connection if one is available.
*/
next_di = &(on->on_dsas);
for(di=on->on_dsas; di!=NULL_DI_BLOCK; di=di->di_next)
{
for(cn=connlist; cn!=NULLCONN; cn=cn->cn_next)
{
/* Must be a suitable context */
if(cn->cn_ctx == CN_CTX_X500_DAP)
{
LLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - open conn has DAP context"));
continue;
}
if((cn->cn_ctx == CN_CTX_X500_DSP)
&& ((on->on_type == ON_TYPE_GET_EDB)
|| (on->on_type == ON_TYPE_GET_DSA_INFO)
|| (cn->cn_initiator == INITIATED_BY_THAT)))
{
if (cn->cn_initiator == INITIATED_BY_THAT)
LLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - open conn has DSP context - we must initiate it"));
else
LLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - open conn has DSP context - QUIPU context needed"));
continue;
}
if((cn->cn_what != NULLDN)
&& (dn_cmp(cn->cn_what, di->di_dn) == 0))
break;
}
if(cn != NULLCONN)
break;
next_di = &(di->di_next);
}
if(di != NULL_DI_BLOCK)
{
/* Got one - remove successful di_block and link op to conn */
DLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - Found suitable open connection"));
(*next_di) = di->di_next;
if (di->di_state == DI_DEFERRED) {
/* We have an open connection, but not a cache entry */
/* (must have used an access point in the past) */
/* Need to be careful about freeing - do it later ! */
di->di_oper = NULLOPER;
} else
di_extract(di);
on->on_conn = cn;
on->on_next_conn = cn->cn_operlist;
cn->cn_operlist = on;
return(OK);
}
/*
* Use a waiting connection if one is available.
*/
next_di = &(on->on_dsas);
for(di=on->on_dsas; di!=NULL_DI_BLOCK; di=di->di_next)
{
for(cn=connwaitlist; cn!=NULLCONN; cn=cn->cn_next)
{
/*
* Could do some clever stuff here and convert a waiting
* connection to QUIPU from X500 if possible and useful.
* Left as an exercise for the reader.
*/
/* Must be a suitable context */
if(cn->cn_ctx == CN_CTX_X500_DAP)
continue;
if((cn->cn_ctx == CN_CTX_X500_DSP)
&& ((on->on_type == ON_TYPE_GET_EDB)
|| (on->on_type == ON_TYPE_GET_DSA_INFO)))
continue;
if((cn->cn_what != NULLDN)
&& (dn_cmp(cn->cn_what, di->di_dn) == 0))
break;
}
if(cn != NULLCONN)
break;
next_di = &(di->di_next);
}
if(di != NULL_DI_BLOCK)
{
/* Got one - remove successful di_block and link op to conn */
LLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - Found suitable waiting connection"));
(*next_di) = di->di_next;
di_extract(di);
on->on_conn = cn;
on->on_next_conn = cn->cn_operlist;
cn->cn_operlist = on;
return(OK);
}
DLOG(log_dsap, LLOG_DEBUG, ("Neither an open nor a waiting conn suitable"));
next_di = &(on->on_dsas);
for(di=on->on_dsas; di!=NULL_DI_BLOCK; di=(*next_di))
{
if(di->di_state == DI_DEFERRED)
{
DLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - deferred di_block"));
next_di = &(di->di_next);
continue;
}
if(di->di_state == DI_ACCESSPOINT)
{
/* context problem:
if we have not got the entry, we don't know which context it
will accept.
If the operation is a getedb, or getdsainfo
ASSUME Quipu context is OK
*/
if((on->on_type == ON_TYPE_GET_EDB)
|| (on->on_type == ON_TYPE_GET_DSA_INFO))
conn_ctx = CN_CTX_QUIPU_DSP;
else {
conn_ctx = CN_CTX_X500_DSP;
}
DLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - make conn block from access point"));
/* There *should* only be one access point -
* but QUIPU may give a choice try find one that will work...
* This is *wrong* if it is a non specific subordinate reference.
*/
if (di->di_reftype == RT_NONSPECIFICSUBORDINATE)
LLOG(log_dsap,LLOG_EXCEPTIONS,("Should try each access point - not just one !!!"));
for (loop_ap=di->di_accesspoints; loop_ap != NULLACCESSPOINT; loop_ap=loop_ap->ap_next)
if((cn = make_conn_block(loop_ap->ap_name, loop_ap->ap_address, conn_ctx)) != NULLCONN)
break;
if (loop_ap == NULLACCESSPOINT) {
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - make_conn_block failed 1"));
(*next_di) = di->di_next;
di_extract(di);
continue;
}
}
if(di->di_state == DI_COMPLETE)
{
/*
* Open a quipu context connection if possible: this is so if
* the entry for the dsa in question has object class quipuDSA.
*/
if((res = quipu_ctx_supported(di->di_entry)) != 2)
{
if((on->on_type == ON_TYPE_GET_EDB)
|| (on->on_type == ON_TYPE_GET_DSA_INFO)
|| (res == -1)) /* DAP only !!! */
{
/* Ditch this di_block and carry on looking */
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - avoiding non-quipu context for GetEDB"));
(*next_di) = di->di_next;
di_extract(di);
continue;
}
else
{
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - linking to a connection without a quipu context"));
conn_ctx = CN_CTX_X500_DSP;
}
}
else
{
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - linking to a connection with a quipu context"));
conn_ctx = CN_CTX_QUIPU_DSP;
}
DLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - make conn block from entry"));
if((cn = make_conn_block(di->di_dn, di->di_entry->e_dsainfo->dsa_addr, conn_ctx)) == NULLCONN)
{
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - make_conn_block failed 2"));
(*next_di) = di->di_next;
di_extract(di);
continue;
}
}
/*
* Decide whether to request connection or place it
* on the list of waiting connections.
*/
switch(on->on_type)
{
case ON_TYPE_GET_DSA_INFO:
do_conn = (conns_used < MAX_CONNS);
break;
case ON_TYPE_GET_EDB:
do_conn = (conns_used < (MAX_CONNS - CONNS_RESERVED_DI - CONNS_RESERVED_X500));
break;
default:
do_conn = (conns_used < (MAX_CONNS - CONNS_RESERVED_DI));
break;
}
if(do_conn)
{
DLOG(log_dsap, LLOG_TRACE, ("link_op_to_conn - about to request connection"));
if(conn_request(cn) != OK)
{
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - conn_request failed"));
(*next_di) = di->di_next;
di_extract(di);
continue;
}
DLOG(log_dsap, LLOG_DEBUG, ("link_op_to_conn - conn_request OK"));
cn->cn_next = connlist;
connlist = cn;
conns_used++;
}
else
{
DLOG(log_dsap, LLOG_NOTICE, ("Waiting for a free connection slot"));
cn->cn_next = connwaitlist;
connwaitlist = cn;
}
(*next_di) = di->di_next;
di_extract(di);
on->on_conn = cn;
on->on_next_conn = cn->cn_operlist;
cn->cn_operlist = on;
return(OK);
}
/*
* If we get this far it means that we are waiting for a dsa info
* operation to complete, or there are no di_blocks left to try.
* Callers of link_op_to_conn must check on_dsas to discover which it is.
*/
DLOG(log_dsap, LLOG_NOTICE, ("link_op_to_conn: returning NOTOK"));
return(NOTOK);
}
int oper_chain(on)
struct oper_act * on;
{
if(link_op_to_conn(on) == OK)
{
if(on->on_conn == NULLCONN)
{
DLOG(log_dsap, LLOG_DEBUG, ("oper_chain - link_op_to_conn: OK but no conn"));
}
else
{
DLOG(log_dsap, LLOG_DEBUG, ("oper_chain - link_op_to_conn: OK got conn"));
if(on->on_conn->cn_state == CN_OPEN)
{
DLOG(log_dsap, LLOG_DEBUG, ("oper_chain - link_op_to_conn: OK got open conn"));
if(oper_send_invoke(on) != OK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("oper_chain - oper_send failed"));
/* Have another go? */
return(oper_chain(on));
}
else
{
DLOG(log_dsap, LLOG_DEBUG, ("oper_chain - oper_send succeeded"));
}
}
}
on->on_state = ON_CHAINED;
}
else
{
/*
* If on->on_dsas is empty then chaining has failed
* otherwise the op is deferred.
*/
if(on->on_dsas == NULL_DI_BLOCK)
{
return(NOTOK);
}
on->on_state = ON_DEFERRED;
}
return(OK);
}
int task_chain(tk, di)
register struct task_act * tk;
struct di_block * di;
{
struct oper_act * on;
struct DSError * err = &(tk->tk_resp.resp_err);
struct di_block * di_tmp;
char refer_ok = TRUE;
#ifdef DEBUG
DLOG(log_dsap, LLOG_DEBUG, ("task_chain called with:"));
di_list_log(di);
#endif
/* NB At some point this routine must assign the di_block list to
* either the task (if it is intended to geneate a referral) or to
* an operation hanging off that task if it is intended to chain the
* task. This is fine when there are no deferred di_blocks, but when
* there are then the information they will eventually contain is
* needed to make a full decision on whether to chain or refer.
* This needs a lot of thought to get right, for now the chain/refer
* decision is made once and for all on the basis of the information
* available now. Any information not available is assumed to force a
* referral (the safe option - until network connectivity is considered)!
* THis may introduce the unwelcome effect that a first request to a
* DSA may produce a referral where subsequent requests do not - so much
* for consistency but it won't happen that often if DSA info is cached
* sensibly.
*/
/*
* Generate the referral which the DSA will pass back if
* chaining is disallowed or oper_chain fails for all
* DSAs listed.
*/
sort_dsa_list (&di);
if ((di_tmp = select_refer_dsa (di,tk)) == NULL_DI_BLOCK) {
/* The remote END is probably unable to follow the referral - chain if allowed */
refer_ok = FALSE;
for(di_tmp=di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
{
if(di_tmp->di_state == DI_DEFERRED)
continue;
#ifdef DEBUG
DLOG(log_dsap, LLOG_DEBUG, ("About to call di2cref with:"));
di_log(di_tmp);
#endif
if(di2cref(di_tmp, err, tk->tk_conn->cn_ctx) == OK)
break;
}
} else if (di2cref(di_tmp, err, tk->tk_conn->cn_ctx) != OK)
di_tmp = NULL_DI_BLOCK; /* waiting... */
if(di_tmp == NULL_DI_BLOCK)
{
/*
* Want to generate a referral - but all di_blocks (if any)
* are deferred. Would we be lying too much if we said the
* DSA was "busy" at this point???
*/
ds_error_free (err);
err->dse_type = DSE_SERVICEERROR;
err->ERR_SERVICE.DSE_sv_problem = DSE_SV_BUSY;
di_desist(di);
return(NOTOK);
}
/*
* If it would be inappropriate to chain this operation, then
* generate a referral from the di_block list.
*/
if(chain_ok(tk,refer_ok) == FALSE)
{
DLOG(log_dsap, LLOG_DEBUG, ("Referring!"));
di_desist(di);
return(NOTOK);
}
DLOG(log_dsap, LLOG_DEBUG, ("Chaining!"));
/* Chain. Generate the new operation to send */
if((on = task2oper(tk)) == NULLOPER)
{
DLOG(log_dsap, LLOG_DEBUG, ("Why did task2oper fail??"));
ds_error_free (err);
err->dse_type = DSE_SERVICEERROR;
err->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNAVAILABLE;
di_desist(di);
return(NOTOK);
}
on->on_next_task = tk->tk_operlist;
tk->tk_operlist = on;
on->on_task = tk;
/* Hand control of di_blocks to the operation */
on->on_dsas = di;
for(di_tmp = di; di_tmp != NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
{
di_tmp->di_type = DI_OPERATION;
di_tmp->di_oper = on;
}
if(oper_chain(on) != OK)
{
oper_task_extract(on);
oper_free(on);
return(NOTOK);
}
return(OK);
}
oper_rechain(on)
struct oper_act * on;
{
struct DSE_referral * ref = &(on->on_resp.resp_err.ERR_REFERRAL);
struct continuation_ref * cref;
register struct chain_arg * cha = &(on->on_req.dca_charg);
struct trace_info * ti;
struct di_block * ap2di();
DLOG(log_dsap, LLOG_TRACE, ("Rechain an operation ..."));
cref = ref->DSE_ref_candidates;
if(cref == NULLCONTINUATIONREF)
{
LLOG(log_dsap, LLOG_FATAL, ("No continuation reference to rechain"));
on->on_resp.resp_type = RESP_TYPE_REJ;
return(NOTOK);
}
(void) dn_decode(cref->cr_name);
cha->cha_target = dn_cpy(cref->cr_name);
cha->cha_progress = cref->cr_progress;
cha->cha_aliasderef = ((cha->cha_aliasedrdns = cref->cr_aliasedRDNs) != CR_NOALIASEDRDNS);
cha->cha_returnrefs = FALSE;
cha->cha_domaininfo = NULLPE;
if((cha->cha_reftype = cref->cr_reftype) == RT_UNDEFINED)
cha->cha_reftype = RT_SUPERIOR;
DLOG(log_dsap, LLOG_DEBUG, ("oper_rechain - Setting trace info"));
ti = (struct trace_info *) malloc(sizeof(struct trace_info));
ti->ti_dsa = dn_cpy(on->on_conn->cn_what);
ti->ti_target = dn_cpy(cref->cr_name);
ti->ti_progress = cref->cr_progress;
ti->ti_next = cha->cha_trace;
cha->cha_trace = ti;
if(ti_is_elem(ti,ti->ti_next))
{
DLOG (log_dsap,LLOG_NOTICE,("Loop found in oper_rechain()"));
ds_error_free (&on->on_resp.resp_err);
on->on_resp.resp_err.dse_type = DSE_SERVICEERROR;
on->on_resp.resp_err.ERR_SERVICE.DSE_sv_problem = DSE_SV_LOOPDETECT;
return(NOTOK);
}
oper_conn_extract(on);
/*
* Problem - having converted to di_blocks it is harder to handle referrals
* Set up a single di_block with the address in the parent field ??
*/
di_desist(on->on_dsas);
if (cref->cr_reftype != RT_NONSPECIFICSUBORDINATE)
on->on_dsas = ap2di (cref->cr_accesspoints,cref->cr_name,FALSE,DI_OPERATION,on,cref->cr_reftype);
else {
on->on_dsas = di_alloc();
(void) dn_decode (cref->cr_name);
on->on_dsas->di_target = dn_cpy(cref->cr_name);
(void) dn_decode (cref->cr_accesspoints->ap_name);
on->on_dsas->di_dn = dn_cpy(cref->cr_accesspoints->ap_name);
DLOG(log_dsap, LLOG_DEBUG, ("oper_rechain allocates di_block with dn[%x]", on->on_dsas->di_dn));
on->on_dsas->di_type = DI_OPERATION;
on->on_dsas->di_reftype = RT_NONSPECIFICSUBORDINATE;
on->on_dsas->di_oper = on;
on->on_dsas->di_state = DI_ACCESSPOINT;
on->on_dsas->di_accesspoints = ap_cpy(cref->cr_accesspoints);
on->on_dsas->di_next = NULL_DI_BLOCK;
}
sort_dsa_list (&on->on_dsas); /* might be able to turn DI_ACCESS into DI_COMPLETE */
return(oper_chain(on));
}
struct oper_act * task2oper(tk)
struct task_act * tk;
{
register struct chain_arg * cha = &(tk->tk_req.dca_charg);
struct continuation_ref * cref = tk->tk_resp.resp_err.ERR_REFERRAL.DSE_ref_candidates;
struct trace_info * ti;
struct oper_act * on;
DLOG(log_dsap, LLOG_TRACE, ("Chain a task ..."));
if((on = oper_alloc()) == NULLOPER)
return(NULLOPER);
on->on_type = ON_TYPE_X500;
cha->cha_target = NULLDN;
if(cref->cr_name != NULLDN)
{
cha->cha_target = dn_cpy(cref->cr_name);
}
cha->cha_progress = cref->cr_progress;
cha->cha_aliasderef = ((cha->cha_aliasedrdns = cref->cr_aliasedRDNs) != CR_NOALIASEDRDNS);
cha->cha_returnrefs = FALSE;
cha->cha_domaininfo = NULLPE;
if((cha->cha_reftype = cref->cr_reftype) == RT_UNDEFINED)
cha->cha_reftype = RT_SUPERIOR;
DLOG(log_dsap, LLOG_DEBUG, ("Checking history of op"));
if(tk->tk_conn->cn_ctx == CN_CTX_X500_DAP)
{
DLOG(log_dsap, LLOG_DEBUG, ("... user originated ..."));
cha->cha_originator = dn_cpy(tk->tk_conn->cn_who);
cha->cha_trace = NULLTRACEINFO;
}
if(tk->tk_timed == FALSE)
{
cha->cha_timelimit = NULLCP;
}
else
{
#ifdef CHAIN_ARGS_TIMEOUT
struct UTCtime ut;
tm2ut(gmtime(&(tk->tk_timeout)), &(ut));
cha->cha_timelimit = strdup(utct2str(&ut));
#else
cha->cha_timelimit = NULLCP;
#endif
}
DLOG(log_dsap, LLOG_DEBUG, ("Setting trace info"));
ti = (struct trace_info *) malloc(sizeof(struct trace_info));
ti->ti_dsa = dn_cpy(mydsadn);
ti->ti_target = dn_cpy(cref->cr_name);
ti->ti_progress = cref->cr_progress;
ti->ti_next = cha->cha_trace;
cha->cha_trace = ti;
on->on_arg = &(tk->tk_req);
return(on);
}
int chain_ok(tk,refer_ok)
struct task_act * tk;
char refer_ok;
{
/* if refer_ok is FALSE - we MUST chain unless prevented, otherwise operation will fail */
DLOG (log_dsap,LLOG_TRACE,( "chain_ok: Checking if chaining is ok"));
if ( ! refer_ok) {
DLOG (log_dsap,LLOG_DEBUG,( "We MUST chain"));
if ((tk->tk_conn->cn_ctx != CN_CTX_X500_DAP) && no_dsp_chain)
{
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of NO_DSP_CHAIN"));
return(FALSE);
}
if(tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_CHAININGPROHIBIT)
{
DLOG (log_dsap,LLOG_DEBUG,( "But prohibited"));
return(FALSE);
}
if(tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_LOCALSCOPE)
{
DLOG (log_dsap,LLOG_DEBUG,( "But out of scope"));
return(FALSE);
}
DLOG (log_dsap,LLOG_DEBUG,( "Forced chain OK!"));
return TRUE;
}
if (tk->tk_conn->cn_ctx != CN_CTX_X500_DAP) {
if (no_dsp_chain)
{
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of NO_DSP_CHAIN (2)"));
return(FALSE);
}
if(! (tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_PREFERCHAIN))
{
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of preference"));
return(FALSE);
}
}
if(tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_CHAININGPROHIBIT)
{
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of prohibition"));
return(FALSE);
}
if(tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_LOCALSCOPE)
{
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of scope"));
return(FALSE);
}
switch (tk->tk_req.dca_dsarg.arg_type) {
case OP_ADDENTRY:
case OP_REMOVEENTRY:
case OP_MODIFYRDN:
case OP_MODIFYENTRY:
/* QUIPU DSAs will only allow modification over DAP */
if (!(tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_PREFERCHAIN)) {
DLOG (log_dsap,LLOG_DEBUG,( "Not chaining because of authentication"));
return(FALSE);
}
default:
break;
}
DLOG (log_dsap,LLOG_DEBUG,( "Chain OK!"));
return(TRUE);
}
task_result_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
DLOG(log_dsap, LLOG_TRACE, ("task_result_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("Oper can't wake up (result)extracted task"));
oper_extract(on);
}
else
{
/*
* Were waiting for a remote result and here it is.
* Attempt to tidy up and send result.
*/
tk->tk_result = &(on->on_resp.resp_res);
tk->tk_resp.resp_type = RESP_TYPE_RET;
on->on_resp.ret_type = RET_TYPE_RES;
dsp_cache (&(tk->tk_req.dca_dsarg),&(tk->tk_result->dcr_dsres),tk->tk_conn->cn_ctx, tk->tk_conn->cn_who);
task_conn_extract(tk);
task_result(tk);
oper_extract(on);
task_extract(tk);
}
}
task_error_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
DLOG(log_dsap, LLOG_TRACE, ("task_error_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("Oper can't wake up (error) extracted task"));
oper_extract(on);
}
else
{
/*
* Were waiting for a remote result and got a remote error.
* If it is a referral, then rechain the operation if appropriate
* otherwise return the error.
*/
if ( ! ((on->on_resp.resp_err.dse_type == DSE_SECURITYERROR)
&& (on->on_resp.resp_err.ERR_SECURITY.DSE_sc_problem == DSE_SC_AUTHENTICATION))) {
/* If is not an authenticaton error, swap errors */
ds_error_free(&(tk->tk_resp.resp_err));
tk->tk_error = &(on->on_resp.resp_err);
}
tk->tk_resp.resp_type = RESP_TYPE_RET;
if((on->on_resp.resp_err.dse_type == DSE_DSAREFERRAL)
|| (on->on_resp.resp_err.dse_type == DSE_REFERRAL))
{
DLOG(log_dsap, LLOG_DEBUG, ("Try rechaining"));
if(oper_rechain(on) == OK)
{
DLOG(log_dsap, LLOG_DEBUG, ("Succeeded rechaining"));
return;
}
DLOG(log_dsap, LLOG_DEBUG, ("Failed rechaining"));
}
task_conn_extract(tk);
task_error(tk);
oper_extract(on);
task_extract(tk);
}
}
task_fail_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
struct DSError * err;
DLOG(log_dsap, LLOG_TRACE, ("task_fail_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
if (on->on_state != ON_ABANDONED)
LLOG(log_dsap, LLOG_EXCEPTIONS, ("task_fail_wakeup: no task"));
oper_extract(on);
return;
}
/*
* Were waiting for a remote result and got a remote failure.
* If it is a referral, then rechain the operation if appropriate
* otherwise return the error.
*/
/*
* If the task does not have a suitable referral error set up
* then return serviceError invalid reference.
*/
err = &(tk->tk_resp.resp_err);
if((err->dse_type != DSE_REFERRAL) && (err->dse_type != DSE_DSAREFERRAL))
{
err->dse_type = DSE_SERVICEERROR;
err->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNAVAILABLE;
}
task_conn_extract(tk);
task_error(tk);
oper_conn_extract(on);
oper_task_extract(on);
oper_extract(on);
task_extract(tk);
}
task_dsa_info_wakeup(di)
struct di_block * di;
{
struct task_act * tk = di->di_task;
DLOG(log_dsap, LLOG_TRACE, ("task_dsa_info_wakeup"));
/*
* Were waiting for a reference to return.
* Check if the reference now returned is acceptable.
* If it is return a referral and unwrap everything,
* otherwise try another di_block for the reference.
*/
sort_dsa_list (&di);
if(di2cref(di, &(tk->tk_resp.resp_err), tk->tk_conn->cn_ctx) != OK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("task_dsa_info_wakeup - reference not acceptable"));
/* Remove di_block which generated unwanted referral wait */
if(tk->tk_dsas == NULL_DI_BLOCK)
{
/* No more dsas from which to request info to form referral */
tk->tk_resp.resp_err.dse_type = DSE_SERVICEERROR;
tk->tk_resp.resp_err.ERR_SERVICE.DSE_sv_problem = DSE_SV_INVALIDREFERENCE;
task_conn_extract(tk);
task_error(tk);
task_extract(tk);
return;
}
return;
}
task_conn_extract(tk);
task_error(tk);
task_extract(tk);
}
static struct access_point * di2ap (di)
struct di_block * di;
{
struct access_point *ap;
switch(di->di_state)
{
case DI_ACCESSPOINT:
return (ap_cpy(di->di_accesspoints));
case DI_COMPLETE:
if(di->di_entry == NULLENTRY)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("di2ap - di_entry NULL"));
return NULLACCESSPOINT;
}
if(di->di_entry->e_dsainfo == NULL)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("di2ap - e_dsainfo NULL"));
return NULLACCESSPOINT;
}
if(di->di_entry->e_dsainfo->dsa_addr == NULLPA)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("di2ap - dsa_addr NULL"));
return NULLACCESSPOINT;
}
ap = (struct access_point *) calloc(1, sizeof(struct access_point));
ap->ap_name = dn_cpy(di->di_dn);
ap->ap_address = psap_cpy(di->di_entry->e_dsainfo->dsa_addr);
return (ap);
default:
return NULLACCESSPOINT;
}
}
int di2cref(di, err, ctx)
struct di_block * di;
struct DSError * err;
char ctx;
{
struct continuation_ref * cref;
struct di_block * loop;
struct access_point *ap_append(), *di2ap(), *ap;
#ifdef DEBUG
DLOG(log_dsap, LLOG_TRACE, ("di2cref"));
di_log(di);
#endif
switch(di->di_state)
{
case DI_ACCESSPOINT:
DLOG(log_dsap, LLOG_TRACE, ("di2cref - generating referrral from di_accesspoints"));
/* Should check context */
err->dse_type = DSE_REFERRAL;
err->ERR_REFERRAL.DSE_ref_prefix = NULLDN;
cref = err->ERR_REFERRAL.DSE_ref_candidates = (struct continuation_ref *) calloc(1, sizeof(struct continuation_ref));
cref->cr_accesspoints = ap_cpy(di->di_accesspoints);
cref->cr_name = dn_cpy(di->di_target);
if((cref->cr_rdn_resolved = di->di_rdn_resolved) <= 0)
{
cref->cr_progress.op_resolution_phase = OP_PHASE_NOTSTARTED;
cref->cr_progress.op_nextrdntoberesolved = 0;
}
else
{
cref->cr_progress.op_resolution_phase = OP_PHASE_PROCEEDING;
cref->cr_progress.op_nextrdntoberesolved = di->di_rdn_resolved;
}
cref->cr_aliasedRDNs = di->di_aliasedRDNs;
cref->cr_reftype = di->di_reftype;
break;
case DI_COMPLETE:
DLOG(log_dsap, LLOG_TRACE, ("di2cref - generating referrral from di_entry"));
/* Should check context */
err->dse_type = DSE_REFERRAL;
err->ERR_REFERRAL.DSE_ref_prefix = NULLDN;
cref = err->ERR_REFERRAL.DSE_ref_candidates = (struct continuation_ref *) calloc(1, sizeof(struct continuation_ref));
if ((cref->cr_accesspoints = di2ap (di)) == NULLACCESSPOINT)
return NOTOK;
cref->cr_name = dn_cpy(di->di_target);
if((cref->cr_rdn_resolved = di->di_rdn_resolved) <= 0)
{
cref->cr_progress.op_resolution_phase = OP_PHASE_NOTSTARTED;
cref->cr_progress.op_nextrdntoberesolved = 0;
}
else
{
cref->cr_progress.op_resolution_phase = OP_PHASE_PROCEEDING;
cref->cr_progress.op_nextrdntoberesolved = di->di_rdn_resolved;
}
cref->cr_aliasedRDNs = di->di_aliasedRDNs;
cref->cr_reftype = di->di_reftype;
break;
case DI_DEFERRED:
LLOG(log_dsap, LLOG_NOTICE, ("di2cref - Trying to turn deferred di_block into continuation reference!"));
return(NOTOK);
default:
LLOG(log_dsap, LLOG_EXCEPTIONS, ("di2cref - invalid di_state %d",di->di_state));
return(NOTOK);
}
if (ctx == CN_CTX_QUIPU_DSP) {
/* Make QSSR */
/* append AP's from remaining di_blocks */
LLOG (log_dsap, LLOG_TRACE, ("Making a QSSR"));
for (loop=di->di_next; loop!=NULL_DI_BLOCK; loop=loop->di_next) {
if (( ap = di2ap(loop)) == NULLACCESSPOINT)
return OK; /* Have finished - return OK */
cref->cr_accesspoints = ap_append (cref->cr_accesspoints,ap);
}
}
return OK;
}
oper_fail_wakeup(on)
struct oper_act * on;
{
DLOG(log_dsap, LLOG_TRACE, ("oper_fail_wakeup()"));
/*
* Attempt to perform operation remotely has failed.
* Check the type of operation and take appropriate action.
*/
switch(on->on_type)
{
case ON_TYPE_X500:
task_fail_wakeup(on);
break;
case ON_TYPE_SUBTASK:
subtask_fail_wakeup(on);
break;
case ON_TYPE_BIND_COMPARE:
bind_compare_fail_wakeup(on);
break;
case ON_TYPE_GET_DSA_INFO:
dsa_info_fail_wakeup(on);
break;
case ON_TYPE_NAMESERVICE:
nameservice_fail_wakeup(on);
break;
case ON_TYPE_GET_EDB:
get_edb_fail_wakeup(on);
break;
default:
LLOG(log_dsap, LLOG_EXCEPTIONS, ("oper_fail_wakeup - op has invalid type"));
break;
}
}
subtask_chain(tk)
struct task_act * tk;
{
struct ds_search_task *refer;
struct ds_search_task *nref;
struct ds_search_task * trail = NULL_ST;
struct ds_search_task * st_done();
struct oper_act * on;
struct di_block * di;
struct di_block * di_tmp;
register struct chain_arg * tkcha = &(tk->tk_req.dca_charg);
register struct chain_arg * oncha;
struct trace_info * ti;
struct DSError err;
if(tk->refer_st == NULL_ST)
return;
DLOG(log_dsap, LLOG_TRACE, ("Chain search subtasks ..."));
for(refer = tk->refer_st; refer != NULL_ST; refer = nref)
{
nref = refer->st_next;
if((di = refer->st_di) == NULL_DI_BLOCK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("search referred without di_block list"));
continue;
}
sort_dsa_list (&di);
err.ERR_REFERRAL.DSE_ref_candidates = NULLCONTINUATIONREF;
if ((di_tmp = select_refer_dsa (di,tk)) == NULL_DI_BLOCK) {
/* The remote END is probably unable to follow the referral - chain if allowed */
for(di_tmp=di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
{
if(di_tmp->di_state == DI_DEFERRED)
continue;
#ifdef DEBUG
DLOG(log_dsap, LLOG_DEBUG, ("About to call di2cref with:"));
di_log(di_tmp);
#endif
if(di2cref(di_tmp, &err, tk->tk_conn->cn_ctx) == OK)
break;
}
} else
(void) di2cref(di_tmp, &err, tk->tk_conn->cn_ctx);
on = oper_alloc();
on->on_type = ON_TYPE_SUBTASK;
on->on_dsas = di;
for(di_tmp=di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next)
{
di_tmp->di_type = DI_OPERATION;
di_tmp->di_oper = on;
}
on->on_subtask = refer;
on->on_task = tk;
on->on_next_task = tk->tk_operlist;
tk->tk_operlist = on;
oncha = &(on->on_req.dca_charg);
if(refer->st_alias == NULLDN)
{
oncha->cha_target = dn_cpy(refer->st_baseobject);
}
else
{
oncha->cha_target = dn_cpy(refer->st_alias);
}
if(di->di_rdn_resolved <= 0)
{
oncha->cha_progress.op_resolution_phase = OP_PHASE_NOTSTARTED;
oncha->cha_progress.op_nextrdntoberesolved = 0;
}
else
{
oncha->cha_progress.op_resolution_phase = OP_PHASE_PROCEEDING;
oncha->cha_progress.op_nextrdntoberesolved = di->di_rdn_resolved;
}
oncha->cha_aliasderef = ((oncha->cha_aliasedrdns = di->di_aliasedRDNs) != CR_NOALIASEDRDNS);
if((oncha->cha_reftype = di->di_reftype) == RT_UNDEFINED)
oncha->cha_reftype = RT_SUPERIOR;
oncha->cha_returnrefs = FALSE;
oncha->cha_domaininfo = NULLPE;
if(tk->tk_timed == FALSE)
{
oncha->cha_timelimit = NULLCP;
}
else
{
#ifdef CHAIN_ARGS_TIMEOUT
struct UTCtime ut;
tm2ut(gmtime(&(tk->tk_timeout)), &(ut));
oncha->cha_timelimit = strdup(utct2str(&ut));
#else
oncha->cha_timelimit = NULLCP;
#endif
}
DLOG(log_dsap, LLOG_DEBUG, ("Checking history of op"));
if(tk->tk_conn->cn_ctx == CN_CTX_X500_DAP)
{
DLOG(log_dsap, LLOG_DEBUG, ("... user originated ..."));
oncha->cha_originator = dn_cpy(tk->tk_conn->cn_who);
oncha->cha_trace = NULLTRACEINFO;
}
else
{
oncha->cha_originator = dn_cpy(tk->tk_req.dca_charg.cha_originator);
oncha->cha_trace = ti_cpy(tkcha->cha_trace);
}
DLOG(log_dsap, LLOG_DEBUG, ("Setting trace info"));
ti = (struct trace_info *) malloc(sizeof(struct trace_info));
ti->ti_dsa = dn_cpy(mydsadn);
ti->ti_target = dn_cpy(di->di_target);
if(di->di_rdn_resolved <= 0)
{
ti->ti_progress.op_resolution_phase = OP_PHASE_NOTSTARTED;
ti->ti_progress.op_nextrdntoberesolved = 0;
}
else
{
ti->ti_progress.op_resolution_phase = OP_PHASE_PROCEEDING;
ti->ti_progress.op_nextrdntoberesolved = di->di_rdn_resolved;
}
ti->ti_next = oncha->cha_trace;
oncha->cha_trace = ti;
on->on_req.dca_dsarg = tk->tk_req.dca_dsarg;
on->on_req.dca_dsarg.arg_sr.sra_subset = refer->st_subset;
on->on_req.dca_dsarg.arg_sr.sra_baseobject = dn_cpy (oncha->cha_target);
on->on_arg = &(on->on_req);
DLOG(log_dsap, LLOG_DEBUG, ("Generating search subtask OP"));
if( (tk->tk_ca->ca_servicecontrol.svc_options & SVC_OPT_CHAININGPROHIBIT)
|| (oper_chain(on) != OK))
{
add_cref2poq (&tk->tk_resp.resp_res.dcr_dsres.res_sr, err.ERR_REFERRAL.DSE_ref_candidates);
oper_task_extract(on);
oper_free(on);
if (trail == NULL_ST)
tk->refer_st = st_done(&refer);
else
trail->st_next = st_done (&refer);
} else {
refer->st_cr = err.ERR_REFERRAL.DSE_ref_candidates;
trail = refer;
}
}
if (trail != NULL_ST)
trail->st_next = tk->referred_st;
tk->referred_st = tk->refer_st;
tk->refer_st = NULL_ST;
if((tk->referred_st == NULL_ST) && (tk->tk_state == TK_PASSIVE) && (tk->tk_operlist == NULLOPER))
{
task_conn_extract(tk);
task_result(tk);
task_extract(tk);
}
}
subtask_result_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
struct ds_search_task **next_st;
struct ds_search_task * st;
DLOG(log_dsap, LLOG_TRACE, ("subtask_result_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("Oper can't wake up (result)extracted task"));
oper_extract(on);
}
else
{
/*
* Were waiting for a remote subtask result and here it is.
*/
next_st = &(tk->referred_st);
for(st=tk->referred_st; st!=NULL_ST; st=(*next_st))
{
if(st == on->on_subtask)
break;
next_st = &(st->st_next);
}
if(st == NULL_ST)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("subtask_result_wakeup - subtask lost from referred list"));
}
else
{
/*
* Correlate uncorrelated search results from oper,
* then merge with correlated search results of task.
*/
struct ds_search_result * tk_sr = &(tk->tk_resp.resp_res.dcr_dsres.res_sr);
struct ds_search_result * op_sr = &(on->on_resp.resp_res.dcr_dsres.res_sr);
DLOG(log_dsap, LLOG_DEBUG, ("Collating a search result"));
st_comp_free (st);
(*next_st) = st->st_next;
correlate_search_results(op_sr);
if(tk_sr->srr_next == NULLSRR)
{
DLOG(log_dsap, LLOG_DEBUG, ("Search result unallocated!"));
tk_sr->srr_next = (struct ds_search_result *) calloc(1, sizeof(struct ds_search_result));
tk_sr->srr_next->srr_correlated = TRUE;
tk_sr->srr_next->srr_un.srr_unit = (struct ds_search_unit *) calloc(1, sizeof(struct ds_search_unit));
tk_sr->srr_next->CSR_limitproblem = LSR_NOLIMITPROBLEM;
}
merge_search_results(tk_sr->srr_next, op_sr);
}
oper_extract(on);
if((tk->referred_st == NULL_ST) && (tk->tk_state == TK_PASSIVE) && (tk->tk_operlist == NULLOPER))
{
task_conn_extract(tk);
task_result(tk);
task_extract(tk);
}
}
}
subtask_error_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
struct ds_search_task **next_st;
struct ds_search_task * st;
DLOG(log_dsap, LLOG_TRACE, ("subtask_error_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("Oper can't wake up (error) extracted task"));
oper_extract(on);
}
else
{
/*
* Were waiting for a remote subtask result and got a remote error.
* If it is a referral, then rechain the operation if appropriate
* otherwise dump the subtask and check the task for completion.
*/
ds_error_free(&(tk->tk_resp.resp_err));
tk->tk_error = &(on->on_resp.resp_err);
tk->tk_resp.resp_type = RESP_TYPE_RET;
if((on->on_resp.resp_err.dse_type == DSE_DSAREFERRAL)
|| (on->on_resp.resp_err.dse_type == DSE_REFERRAL))
{
DLOG(log_dsap, LLOG_DEBUG, ("Try rechaining st"));
if(oper_rechain(on) == OK)
{
DLOG(log_dsap, LLOG_DEBUG, ("Succeeded rechaining st"));
return;
}
DLOG(log_dsap, LLOG_DEBUG, ("Failed rechaining st"));
add_cref2poq (&tk->tk_resp.resp_res.dcr_dsres.res_sr, on->on_resp.resp_err.ERR_REFERRAL.DSE_ref_candidates);
on->on_resp.resp_err.ERR_REFERRAL.DSE_ref_candidates = NULLCONTINUATIONREF;
}
next_st = &(tk->referred_st);
for(st=tk->referred_st; st!=NULL_ST; st=(*next_st))
{
if(st == on->on_subtask)
break;
next_st = &(st->st_next);
}
if(st == NULL_ST)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("subtask_result_wakeup - subtask lost from referred list"));
}
else
{
st_comp_free (st);
(*next_st) = st->st_next;
}
oper_extract(on);
if((tk->referred_st == NULL_ST) && (tk->tk_state == TK_PASSIVE) && (tk->tk_operlist == NULLOPER))
{
task_conn_extract(tk);
task_result(tk);
task_extract(tk);
}
}
}
subtask_fail_wakeup(on)
struct oper_act * on;
{
struct task_act * tk;
struct DSError * err;
struct ds_search_task **next_st;
struct ds_search_task * st;
DLOG(log_dsap, LLOG_TRACE, ("subtask_fail_wakeup"));
if((tk = on->on_task) == NULLTASK)
{
LLOG(log_dsap, LLOG_FATAL, ("subtask_fail_wakeup: no task"));
oper_extract(on);
return;
}
else
{
next_st = &(tk->referred_st);
for(st=tk->referred_st; st!=NULL_ST; st=(*next_st))
{
if(st == on->on_subtask)
break;
next_st = &(st->st_next);
}
if(st == NULL_ST)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("subtask_result_wakeup - subtask lost from referred list"));
}
else
{
add_cref2poq (&tk->tk_resp.resp_res.dcr_dsres.res_sr, st->st_cr);
st_comp_free (st);
(*next_st) = st->st_next;
}
oper_extract(on);
if((tk->referred_st == NULL_ST) && (tk->tk_state == TK_PASSIVE) && (tk->tk_operlist == NULLOPER))
{
task_conn_extract(tk);
task_result(tk);
task_extract(tk);
}
}
err = &(tk->tk_resp.resp_err);
if((err->dse_type != DSE_REFERRAL) && (err->dse_type != DSE_DSAREFERRAL))
{
err->dse_type = DSE_SERVICEERROR;
err->ERR_SERVICE.DSE_sv_problem = DSE_SV_UNAVAILABLE;
}
}
subtask_dsa_info_wakeup(di)
struct di_block * di;
{
struct task_act * tk = di->di_task;
DLOG(log_dsap, LLOG_TRACE, ("subtask_dsa_info_wakeup"));
/*
* Were waiting for a reference to return.
* Check if the reference now returned is acceptable.
* If it is return a referral and unwrap everything,
* otherwise try another di_block for the reference.
*/
if(di2cref(di, &(tk->tk_resp.resp_err), tk->tk_conn->cn_ctx) != OK)
{
LLOG(log_dsap, LLOG_EXCEPTIONS, ("subtask_dsa_info_wakeup - reference not acceptable"));
/* Remove di_block which generated unwanted referral wait */
if(tk->tk_dsas == NULL_DI_BLOCK)
{
/* No more dsas from which to request info to form referral */
tk->tk_resp.resp_err.dse_type = DSE_SERVICEERROR;
tk->tk_resp.resp_err.ERR_SERVICE.DSE_sv_problem = DSE_SV_INVALIDREFERENCE;
task_conn_extract(tk);
task_error(tk);
task_extract(tk);
return;
}
return;
}
task_conn_extract(tk);
task_error(tk);
task_extract(tk);
}
add_cref2poq (res,cref)
struct ds_search_result *res;
ContinuationRef cref;
{
ContinuationRef cr;
if (res->CSR_cr == NULLCONTINUATIONREF) {
res->CSR_cr = cref;
return;
}
for (cr = res->CSR_cr; cr->cr_next != NULLCONTINUATIONREF; cr=cr->cr_next)
;
cr->cr_next = cref;
}