Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / contrib / isode / quipu / task_select.c
CommitLineData
fc4ef1d0
C
1/* task_select.c - tidy connection mesh and select next DSA activity */
2
3#ifndef lint
4static char *rcsid = "$Header: /f/osi/quipu/RCS/task_select.c,v 7.5 91/03/09 11:57:09 mrose Exp $";
5#endif
6
7/*
8 * $Header: /f/osi/quipu/RCS/task_select.c,v 7.5 91/03/09 11:57:09 mrose Exp $
9 *
10 *
11 * $Log: task_select.c,v $
12 * Revision 7.5 91/03/09 11:57:09 mrose
13 * update
14 *
15 * Revision 7.4 91/02/22 09:40:02 mrose
16 * Interim 6.8
17 *
18 * Revision 7.3 90/10/17 11:54:56 mrose
19 * sync
20 *
21 * Revision 7.2 90/07/09 14:46:43 mrose
22 * sync
23 *
24 * Revision 7.1 89/12/19 16:20:51 mrose
25 * sync
26 *
27 * Revision 7.0 89/11/23 22:18:15 mrose
28 * Release 6.0
29 *
30 */
31
32/*
33 * NOTICE
34 *
35 * Acquisition, use, and distribution of this module and related
36 * materials are subject to the restrictions of a license agreement.
37 * Consult the Preface in the User's Manual for the full terms of
38 * this agreement.
39 *
40 */
41
42
43#include "quipu/util.h"
44#include "quipu/connection.h"
45
46extern LLog * log_dsap;
47extern time_t conn_timeout;
48extern time_t nsap_timeout;
49extern time_t slave_timeout;
50extern time_t time();
51extern time_t timenow;
52time_t lastedb_update;
53struct oper_act * pending_ops = NULLOPER;
54
55struct task_act * task_select(secs_p)
56int * secs_p;
57{
58 struct connection * cn;
59 struct connection * cn_tmp;
60 struct connection **next_cn;
61 struct task_act * tk;
62 struct task_act **next_tk;
63 struct oper_act * on;
64 int timeout_tmp;
65 char process_edbs = TRUE;
66 char do_timeout;
67 int suspended = FALSE;
68 struct task_act * ret_tk = NULLTASK;
69 extern char startup_update;
70
71 (void) time (&timenow);
72 (*secs_p) = NOTOK;
73 conns_used = 0;
74
75/*
76 DLOG(log_dsap, LLOG_DEBUG, ("task_select connections:"));
77 conn_list_log(connlist);
78*/
79
80 for(cn=connlist; cn!=NULLCONN; cn=cn_tmp)
81 {
82 cn_tmp = cn->cn_next; /* Nasty but necessary in conn_extract()
83 manages to get itself called somehow */
84
85 do_timeout = FALSE;
86
87 conn_log(cn);
88
89 next_tk = &(cn->cn_tasklist);
90 for(tk=cn->cn_tasklist; tk!=NULLTASK; tk=(*next_tk))
91 {
92 if(tk->tk_timed)
93 {
94 if(tk->tk_timeout <= timenow)
95 {
96#ifdef DEBUG
97 struct UTCtime ut;
98 struct UTCtime ut2;
99
100 DLOG(log_dsap, LLOG_TRACE, ("task has timelimit of %ld", tk->tk_timeout));
101 tm2ut(gmtime(&(tk->tk_timeout)), &ut);
102 DLOG(log_dsap, LLOG_DEBUG, ("converted timelimit = %s", utct2str(&(ut))));
103 tm2ut(gmtime(&(timenow)), &ut2);
104 DLOG(log_dsap, LLOG_DEBUG, ("time now = %s", utct2str(&(ut2))));
105#endif
106 (*next_tk) = tk->tk_next;
107 timeout_task(tk);
108 continue;
109 }
110 else
111 {
112 timeout_tmp = (int) tk->tk_timeout - timenow;
113 if(((*secs_p) == NOTOK) || ((*secs_p) > timeout_tmp))
114 {
115 (*secs_p) = timeout_tmp;
116 }
117 }
118 }
119
120 next_tk = &(tk->tk_next);
121 }
122
123 if(cn->cn_state == CN_OPEN)
124 {
125 next_tk = &(cn->cn_tasklist);
126 for(tk=cn->cn_tasklist; tk!=NULLTASK; tk=(*next_tk))
127 {
128 next_tk = &(tk->tk_next);
129
130 if(tk->tk_state == TK_ACTIVE)
131 {
132 if( (ret_tk == NULLTASK)
133 || (tk->tk_prio > ret_tk->tk_prio)
134 || ( (tk->tk_prio == ret_tk->tk_prio)
135 && ( (!ret_tk->tk_timed)
136 || ( (tk->tk_timed)
137 && (tk->tk_timeout < ret_tk->tk_timeout)
138 )
139 )
140 )
141 )
142 {
143 ret_tk = tk;
144 }
145 }
146
147 if(tk->tk_state == TK_SUSPEND)
148 {
149 /*
150 * A task suspended to allow the network to be polled.
151 * Set suspended to force polling.
152 */
153 tk->tk_state = TK_ACTIVE;
154 suspended = TRUE;
155 }
156 }
157
158 if(cn->cn_tasklist == NULLTASK)
159 {
160 if(cn->cn_initiator)
161 {
162 if(cn->cn_operlist == NULLOPER)
163 {
164 if((cn->cn_last_used + conn_timeout) <= timenow)
165 {
166 do_timeout = TRUE;
167 }
168 else
169 {
170 timeout_tmp = (int) (cn->cn_last_used + conn_timeout) - timenow;
171 if(((*secs_p) == NOTOK) || ((*secs_p) > timeout_tmp))
172 {
173 (*secs_p) = timeout_tmp;
174 }
175 }
176 }
177 else
178 {
179 timeout_tmp = conn_timeout; /* safety catch */
180 if ((tk = cn->cn_operlist->on_task) != NULLTASK) {
181 if (tk->tk_timed) {
182 timeout_tmp = (int) tk->tk_timeout - timenow;
183 if (timeout_tmp < 0)
184 timeout_tmp = 0;
185 }
186 }
187 if(((*secs_p) == NOTOK) || ((*secs_p) > timeout_tmp))
188 {
189 (*secs_p) = timeout_tmp;
190 }
191 cn->cn_last_used = timenow;
192 }
193 }
194 }
195 else
196 {
197 cn->cn_last_used = timenow;
198 process_edbs = FALSE;
199 }
200 } else {
201 if((cn->cn_last_used + nsap_timeout) <= timenow)
202 {
203 if ((cn->cn_state == CN_CONNECTING1) || (cn->cn_state == CN_CONNECTING2))
204 conn_retry(cn);
205 else if (cn->cn_state == CN_CLOSING) {
206 if (conn_release_retry(cn) == NOTOK) {
207 /* had its chance - abort */
208 do_ds_unbind(cn);
209 conn_rel_abort (cn);
210 conn_extract(cn);
211 }
212 } else if (cn->cn_state == CN_OPENING) {
213 /* something started to associate - then gave up !!! */
214 conn_rel_abort (cn);
215 conn_extract (cn);
216 }
217 (*secs_p) = nsap_timeout;
218 }
219 else
220 {
221 timeout_tmp = (int) (cn->cn_last_used + nsap_timeout) - timenow;
222 if(((*secs_p) == NOTOK) || ((*secs_p) > timeout_tmp))
223 {
224 (*secs_p) = timeout_tmp;
225 }
226 }
227 }
228
229 if(do_timeout)
230 {
231 LLOG(log_dsap, LLOG_NOTICE, ("Timing out connection %d",cn->cn_ad));
232 if (conn_release(cn) == NOTOK) {
233 (*secs_p) = nsap_timeout;
234 conns_used++;
235 }
236 }
237 else
238 {
239 conns_used++;
240 }
241 }
242
243/*
244* Open the connection with the highest priority operation
245* waiting on it...
246*
247* Get DSA Info operations are highest priority, followed by
248* BIND_COMPARE, and X500, and finally GetEDB operations.
249*/
250 next_cn = &(connwaitlist);
251 for(cn=connwaitlist; cn!=NULLCONN; cn=(*next_cn))
252 {
253 if(conns_used >= MAX_CONNS)
254 break;
255
256 for(on=cn->cn_operlist; on!=NULLOPER; on=on->on_next_conn)
257 {
258 if(on->on_type == ON_TYPE_GET_DSA_INFO)
259 {
260 (*next_cn) = cn->cn_next;
261 if(conn_request(cn) == OK)
262 {
263 conns_used++;
264 cn->cn_next = connlist;
265 connlist = cn;
266 cn->cn_last_used = timenow;
267 /* Do something with the operations */
268 }
269 else
270 {
271 /* Do something with the operations */
272 }
273 break;
274 }
275 }
276 if(on == NULLOPER)
277 next_cn = &(cn->cn_next);
278 }
279
280 next_cn = &(connwaitlist);
281 for(cn=connwaitlist; cn!=NULLCONN; cn=(*next_cn))
282 {
283 if(conns_used >= (MAX_CONNS - CONNS_RESERVED_DI))
284 break;
285
286 for(on=cn->cn_operlist; on!=NULLOPER; on=on->on_next_conn)
287 {
288 if(on->on_type != ON_TYPE_GET_EDB)
289 {
290 (*next_cn) = cn->cn_next;
291 if(conn_request(cn) == OK)
292 {
293 conns_used++;
294 cn->cn_next = connlist;
295 connlist = cn;
296 cn->cn_last_used = timenow;
297 /* Do something with the operations */
298 }
299 else
300 {
301 /* Do something with the operations */
302 }
303 break;
304 }
305 }
306 if(on == NULLOPER)
307 next_cn = &(cn->cn_next);
308 }
309
310 next_cn = &(connwaitlist);
311 for(cn=connwaitlist; cn!=NULLCONN; cn=(*next_cn))
312 {
313 if(conns_used >= (MAX_CONNS - CONNS_RESERVED_DI - CONNS_RESERVED_X500))
314 break;
315
316 (*next_cn) = cn->cn_next;
317 if(conn_request(cn) == OK)
318 {
319 conns_used++;
320 cn->cn_next = connlist;
321 connlist = cn;
322 cn->cn_last_used = timenow;
323 /* Do something with the operations */
324 }
325 else
326 {
327 /* Do something with the operations */
328 }
329 }
330
331 if(process_edbs) {
332 /*
333 * Nothing is happening that would be disturbed by writing back
334 * a retrieved EDB so it is a good time to process them.
335 */
336
337 if (!get_edb_ops && pending_ops) {
338
339 get_edb_ops = pending_ops;
340 pending_ops = NULLOPER;
341
342 if(oper_chain(get_edb_ops) != OK)
343 {
344 LLOG(log_dsap, LLOG_NOTICE, ("Could not chain a pending operation"));
345 (*secs_p) = 0; /* service network and then try next one */
346
347 pending_ops = get_edb_ops -> on_next_task;
348 get_edb_ops -> on_next_task = NULLOPER;
349 oper_free(get_edb_ops);
350 get_edb_ops = NULLOPER;
351 }
352 }
353 else if (get_edb_ops)
354 {
355 if (get_edb_ops->on_state == ON_COMPLETE)
356 {
357 if (get_edb_ops->on_type == ON_TYPE_GET_EDB)
358 process_edb(get_edb_ops);
359 else /* ON_TYPE_SHADOW */
360 process_shadow(get_edb_ops);
361
362 if (get_edb_ops) {
363 pending_ops = get_edb_ops->on_next_task;
364 get_edb_ops->on_next_task = NULLOPER;
365
366 oper_conn_extract(get_edb_ops);
367 oper_free(get_edb_ops);
368
369 get_edb_ops = NULLOPER;
370 }
371 (*secs_p) = 0; /* Schedule next one ! */
372
373 } else if (get_edb_ops->on_state == ON_ABANDONED) {
374 LLOG (log_dsap,LLOG_NOTICE,("Get edb has been abandoned"));
375
376 pending_ops = get_edb_ops->on_next_task;
377 get_edb_ops->on_next_task = NULLOPER;
378
379 oper_free(get_edb_ops);
380
381 get_edb_ops = NULLOPER;
382 (*secs_p) = 0; /* Schedule next one ! */
383 }
384
385 } else if (startup_update) {
386 /* see if cache timer has expired - if so resend edb ops... */
387 if ( (timenow - lastedb_update) >= slave_timeout )
388 slave_update();
389 }
390 }
391
392 if ((get_edb_ops == NULLOPER) && startup_update ) {
393 /* make sure we are awake for the next EDB update */
394 if ((timeout_tmp = lastedb_update + slave_timeout - timenow) >= 0)
395 if (((*secs_p) == NOTOK) || ((*secs_p) > timeout_tmp))
396 (*secs_p) = timeout_tmp;
397 }
398
399 if(suspended)
400 {
401 /*
402 * A task suspended in order for the network to be checked.
403 * Force this to happen by setting the selected task to NULL
404 * and the polling time of the network to 0 secs.
405 */
406 ret_tk = NULLTASK;
407 (*secs_p) = 0;
408 }
409
410 return(ret_tk);
411}
412
413timeout_task(tk)
414struct task_act * tk;
415{
416 struct oper_act * on;
417 struct DSError * err = &(tk->tk_resp.di_error.de_err);
418 struct ds_search_task *tmp;
419
420 DLOG(log_dsap, LLOG_TRACE, ("timeout_task"));
421 for(on=tk->tk_operlist; on!=NULLOPER; on=on->on_next_task)
422 {
423 /* Time out operations started by task */
424 on->on_state = ON_ABANDONED;
425 on->on_task = NULLTASK;
426 }
427
428 if(tk->tk_dx.dx_arg.dca_dsarg.arg_type != OP_SEARCH)
429 {
430 err->dse_type = DSE_SERVICEERROR;
431 if (tk->tk_timed == TRUE)
432 err->ERR_SERVICE.DSE_sv_problem = DSE_SV_TIMELIMITEXCEEDED;
433 else /* tk->tk_timed == 2 */
434 err->ERR_SERVICE.DSE_sv_problem = DSE_SV_ADMINLIMITEXCEEDED;
435 task_error(tk);
436 task_extract(tk);
437 }
438 else
439 {
440 /* Do search collation */
441 if ((tk->tk_state == TK_ACTIVE) && (tk->local_st == NULL_ST)) {
442 /* nothing happened yet... */
443 err->dse_type = DSE_SERVICEERROR;
444 if (tk->tk_timed == TRUE)
445 err->ERR_SERVICE.DSE_sv_problem = DSE_SV_TIMELIMITEXCEEDED;
446 else /* tk->tk_timed == 2 */
447 err->ERR_SERVICE.DSE_sv_problem = DSE_SV_ADMINLIMITEXCEEDED;
448 task_error(tk);
449 } else {
450 /* send the results we have got... */
451 tk->tk_result = &(tk->tk_resp.di_result.dr_res);
452 tk->tk_result->dcr_dsres.result_type = tk->tk_dx.dx_arg.dca_dsarg.arg_type;
453 tk->tk_resp.di_type = DI_RESULT;
454 if (tk->tk_timed == TRUE)
455 tk->tk_resp.di_result.dr_res.dcr_dsres.res_sr.CSR_limitproblem = LSR_TIMELIMITEXCEEDED;
456 else /* tk->tk_timed == 2 */
457 tk->tk_resp.di_result.dr_res.dcr_dsres.res_sr.CSR_limitproblem = LSR_ADMINSIZEEXCEEDED;
458
459 /* Go through sub-tasks and add a POQ for each */
460 for(tmp=tk->referred_st; tmp!= NULL_ST; tmp=tmp->st_next)
461 add_cref2poq (&tk->tk_result->dcr_dsres.res_sr,tmp->st_cr);
462
463 task_result(tk);
464 }
465 task_extract(tk);
466 }
467
468}
469
470
471schedule_operation (x)
472register struct oper_act *x;
473{
474register struct oper_act * on;
475
476 if (on = pending_ops) /* assign */ {
477 for ( ; on->on_next_task != NULLOPER; on = on->on_next_task)
478 ;
479 on->on_next_task = x;
480 } else
481 pending_ops = x;
482}