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