Commit | Line | Data |
---|---|---|
fc4ef1d0 C |
1 | /* task_select.c - tidy connection mesh and select next DSA activity */ |
2 | ||
3 | #ifndef lint | |
4 | static 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 | ||
46 | extern LLog * log_dsap; | |
47 | extern time_t conn_timeout; | |
48 | extern time_t nsap_timeout; | |
49 | extern time_t slave_timeout; | |
50 | extern time_t time(); | |
51 | extern time_t timenow; | |
52 | time_t lastedb_update; | |
53 | struct oper_act * pending_ops = NULLOPER; | |
54 | ||
55 | struct task_act * task_select(secs_p) | |
56 | int * 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 | ||
413 | timeout_task(tk) | |
414 | struct 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 | ||
471 | schedule_operation (x) | |
472 | register struct oper_act *x; | |
473 | { | |
474 | register 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 | } |