Branch data Line data Source code
1 : : /*
2 : : SSSD
3 : :
4 : : Data Provider Helpers
5 : :
6 : : Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
7 : :
8 : : This program is free software; you can redistribute it and/or modify
9 : : it under the terms of the GNU General Public License as published by
10 : : the Free Software Foundation; either version 3 of the License, or
11 : : (at your option) any later version.
12 : :
13 : : This program is distributed in the hope that it will be useful,
14 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : GNU General Public License for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : : */
21 : :
22 : : #include <netdb.h>
23 : : #include <arpa/inet.h>
24 : : #include "providers/dp_backend.h"
25 : : #include "resolv/async_resolv.h"
26 : :
27 : : struct be_svc_callback {
28 : : struct be_svc_callback *prev;
29 : : struct be_svc_callback *next;
30 : :
31 : : struct be_svc_data *svc;
32 : :
33 : : be_svc_callback_fn_t *fn;
34 : : void *private_data;
35 : : };
36 : :
37 : : struct be_svc_data {
38 : : struct be_svc_data *prev;
39 : : struct be_svc_data *next;
40 : :
41 : : const char *name;
42 : : struct fo_service *fo_service;
43 : :
44 : : struct fo_server *last_good_srv;
45 : : time_t last_status_change;
46 : : bool run_callbacks;
47 : :
48 : : struct be_svc_callback *callbacks;
49 : : struct fo_server *first_resolved;
50 : : };
51 : :
52 : : struct be_failover_ctx {
53 : : struct fo_ctx *fo_ctx;
54 : : struct resolv_ctx *resolv;
55 : :
56 : : struct be_svc_data *svcs;
57 : : struct tevent_timer *primary_server_handler;
58 : : };
59 : :
60 : : static const char *proto_table[] = { FO_PROTO_TCP, FO_PROTO_UDP, NULL };
61 : :
62 : 0 : int be_fo_is_srv_identifier(const char *server)
63 : : {
64 [ # # ][ # # ]: 0 : return server && strcasecmp(server, BE_SRV_IDENTIFIER) == 0;
65 : : }
66 : :
67 : 0 : static int be_fo_get_options(struct be_ctx *ctx,
68 : : struct fo_options *opts)
69 : : {
70 : : errno_t ret;
71 : :
72 : 0 : ret = confdb_get_int(ctx->cdb, ctx->conf_path,
73 : : CONFDB_DOMAIN_RESOLV_TIMEOUT,
74 : : FO_DEFAULT_SVC_TIMEOUT,
75 : : &opts->service_resolv_timeout);
76 [ # # ]: 0 : if (ret != EOK) {
77 : : return ret;
78 : : }
79 : :
80 : 0 : opts->retry_timeout = 30;
81 : 0 : opts->srv_retry_timeout = 14400;
82 : :
83 : 0 : ret = resolv_get_family_order(ctx->cdb, ctx->conf_path,
84 : : &opts->family_order);
85 [ # # ]: 0 : if (ret != EOK) {
86 : : return ret;
87 : : }
88 : :
89 : : return EOK;
90 : : }
91 : :
92 : 0 : int be_init_failover(struct be_ctx *ctx)
93 : : {
94 : : int ret;
95 : : int resolv_timeout;
96 : : struct fo_options fopts;
97 : :
98 [ # # ]: 0 : if (ctx->be_fo != NULL) {
99 : : return EOK;
100 : : }
101 : :
102 : 0 : ctx->be_fo = talloc_zero(ctx, struct be_failover_ctx);
103 [ # # ]: 0 : if (!ctx->be_fo) {
104 : : return ENOMEM;
105 : : }
106 : :
107 : 0 : ret = confdb_get_int(ctx->cdb, ctx->conf_path,
108 : : CONFDB_DOMAIN_RESOLV_OP_TIMEOUT,
109 : : RESOLV_DEFAULT_TIMEOUT, &resolv_timeout);
110 [ # # ]: 0 : if (ret != EOK) {
111 : : return ret;
112 : : }
113 : :
114 : 0 : ret = resolv_init(ctx, ctx->ev, resolv_timeout, &ctx->be_fo->resolv);
115 [ # # ]: 0 : if (ret != EOK) {
116 : 0 : talloc_zfree(ctx->be_fo);
117 : : return ret;
118 : : }
119 : :
120 : 0 : ret = be_fo_get_options(ctx, &fopts);
121 [ # # ]: 0 : if (ret != EOK) {
122 : 0 : talloc_zfree(ctx->be_fo);
123 : : return ret;
124 : : }
125 : :
126 : 0 : ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, &fopts);
127 [ # # ]: 0 : if (!ctx->be_fo->fo_ctx) {
128 : 0 : talloc_zfree(ctx->be_fo);
129 : : return ENOMEM;
130 : : }
131 : :
132 : : return EOK;
133 : : }
134 : :
135 : 0 : static int be_svc_data_destroy(void *memptr)
136 : : {
137 : : struct be_svc_data *svc;
138 : :
139 : 0 : svc = talloc_get_type(memptr, struct be_svc_data);
140 : :
141 [ # # ]: 0 : while (svc->callbacks) {
142 : : /* callbacks removes themselves from the list,
143 : : * so this while will freem them all and then terminate */
144 : 0 : talloc_free(svc->callbacks);
145 : : }
146 : :
147 : 0 : return 0;
148 : : }
149 : :
150 : : /*
151 : : * Find registered be_svc_data by service name.
152 : : */
153 : 0 : static struct be_svc_data *be_fo_find_svc_data(struct be_ctx *ctx,
154 : : const char *service_name)
155 : : {
156 : : struct be_svc_data *svc;
157 : :
158 [ # # ][ # # ]: 0 : if (!ctx || !ctx->be_fo) {
159 : : return 0;
160 : : }
161 : :
162 [ # # ]: 0 : DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
163 [ # # ]: 0 : if (strcmp(svc->name, service_name) == 0) {
164 : : return svc;
165 : : }
166 : : }
167 : :
168 : : return 0;
169 : : }
170 : :
171 : 0 : int be_fo_add_service(struct be_ctx *ctx, const char *service_name,
172 : : datacmp_fn user_data_cmp)
173 : : {
174 : : struct fo_service *service;
175 : : struct be_svc_data *svc;
176 : : int ret;
177 : :
178 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
179 [ # # ]: 0 : if (svc) {
180 [ # # ][ # # ]: 0 : DEBUG(6, ("Failover service already initialized!\n"));
[ # # ][ # # ]
[ # # ]
181 : : /* we already have a service up and configured,
182 : : * can happen when using both id and auth provider
183 : : */
184 : : return EOK;
185 : : }
186 : :
187 : : /* if not in the be service list, try to create new one */
188 : :
189 : 0 : ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, user_data_cmp,
190 : : &service);
191 [ # # ]: 0 : if (ret != EOK && ret != EEXIST) {
192 [ # # ][ # # ]: 0 : DEBUG(1, ("Failed to create failover service!\n"));
[ # # ][ # # ]
[ # # ]
193 : : return ret;
194 : : }
195 : :
196 : 0 : svc = talloc_zero(ctx->be_fo, struct be_svc_data);
197 [ # # ]: 0 : if (!svc) {
198 : : return ENOMEM;
199 : : }
200 : 0 : talloc_set_destructor((TALLOC_CTX *)svc, be_svc_data_destroy);
201 : :
202 : 0 : svc->name = talloc_strdup(svc, service_name);
203 [ # # ]: 0 : if (!svc->name) {
204 : 0 : talloc_zfree(svc);
205 : : return ENOMEM;
206 : : }
207 : 0 : svc->fo_service = service;
208 : :
209 [ # # ]: 0 : DLIST_ADD(ctx->be_fo->svcs, svc);
210 : :
211 : : return EOK;
212 : : }
213 : :
214 : 0 : static int be_svc_callback_destroy(void *memptr)
215 : : {
216 : : struct be_svc_callback *callback;
217 : :
218 : 0 : callback = talloc_get_type(memptr, struct be_svc_callback);
219 : :
220 [ # # ]: 0 : if (callback->svc) {
221 [ # # ][ # # ]: 0 : DLIST_REMOVE(callback->svc->callbacks, callback);
[ # # ][ # # ]
[ # # ]
222 : : }
223 : :
224 : 0 : return 0;
225 : : }
226 : :
227 : 0 : int be_fo_service_add_callback(TALLOC_CTX *memctx,
228 : : struct be_ctx *ctx, const char *service_name,
229 : : be_svc_callback_fn_t *fn, void *private_data)
230 : : {
231 : : struct be_svc_callback *callback;
232 : : struct be_svc_data *svc;
233 : :
234 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
235 [ # # ]: 0 : if (NULL == svc) {
236 : : return ENOENT;
237 : : }
238 : :
239 : 0 : callback = talloc_zero(memctx, struct be_svc_callback);
240 [ # # ]: 0 : if (!callback) {
241 : : return ENOMEM;
242 : : }
243 : 0 : talloc_set_destructor((TALLOC_CTX *)callback, be_svc_callback_destroy);
244 : :
245 : 0 : callback->svc = svc;
246 : 0 : callback->fn = fn;
247 : 0 : callback->private_data = private_data;
248 : :
249 [ # # ]: 0 : DLIST_ADD(svc->callbacks, callback);
250 : :
251 : : return EOK;
252 : : }
253 : :
254 : 0 : int be_fo_add_srv_server(struct be_ctx *ctx,
255 : : const char *service_name,
256 : : const char *query_service,
257 : : const char *default_discovery_domain,
258 : : enum be_fo_protocol proto,
259 : : bool proto_fallback, void *user_data)
260 : : {
261 : : struct be_svc_data *svc;
262 : : char *domain;
263 : : int ret;
264 : : int i;
265 : :
266 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
267 [ # # ]: 0 : if (NULL == svc) {
268 : : return ENOENT;
269 : : }
270 : :
271 : 0 : ret = confdb_get_string(ctx->cdb, svc, ctx->conf_path,
272 : : CONFDB_DOMAIN_DNS_DISCOVERY_NAME,
273 : : default_discovery_domain, &domain);
274 [ # # ]: 0 : if (ret != EOK) {
275 [ # # ][ # # ]: 0 : DEBUG(1, ("Failed reading %s from confdb\n",
[ # # ][ # # ]
[ # # ]
276 : : CONFDB_DOMAIN_DNS_DISCOVERY_NAME));
277 : : return ret;
278 : : }
279 : :
280 : : /* Add the first protocol as the primary lookup */
281 : 0 : ret = fo_add_srv_server(svc->fo_service, query_service,
282 : 0 : domain, ctx->domain->name,
283 : : proto_table[proto], user_data);
284 [ # # ]: 0 : if (ret && ret != EEXIST) {
285 [ # # ][ # # ]: 0 : DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
[ # # ][ # # ]
[ # # ]
286 : : return ret;
287 : : }
288 : :
289 [ # # ]: 0 : if (proto_fallback) {
290 : 0 : i = (proto + 1) % BE_FO_PROTO_SENTINEL;
291 : : /* All the rest as fallback */
292 [ # # ]: 0 : while (i != proto) {
293 : 0 : ret = fo_add_srv_server(svc->fo_service, query_service,
294 : 0 : domain, ctx->domain->name,
295 : : proto_table[i], user_data);
296 [ # # ]: 0 : if (ret && ret != EEXIST) {
297 [ # # ][ # # ]: 0 : DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));
[ # # ][ # # ]
[ # # ]
298 : : return ret;
299 : : }
300 : :
301 : 0 : i = (i + 1) % BE_FO_PROTO_SENTINEL;
302 : : }
303 : : }
304 : :
305 : : return EOK;
306 : : }
307 : :
308 : 0 : int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
309 : : {
310 : : struct be_svc_data *svc_data;
311 : :
312 : 0 : svc_data = be_fo_find_svc_data(ctx, service_name);
313 [ # # ]: 0 : if (!svc_data) {
314 : : return 0;
315 : : }
316 : :
317 : 0 : return fo_get_server_count(svc_data->fo_service);
318 : : }
319 : :
320 : 0 : int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
321 : : const char *server, int port, void *user_data,
322 : : bool primary)
323 : : {
324 : : struct be_svc_data *svc;
325 : : int ret;
326 : :
327 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
328 [ # # ]: 0 : if (NULL == svc) {
329 : : return ENOENT;
330 : : }
331 : :
332 : 0 : ret = fo_add_server(svc->fo_service, server, port,
333 : : user_data, primary);
334 [ # # ]: 0 : if (ret && ret != EEXIST) {
335 [ # # ][ # # ]: 0 : DEBUG(1, ("Failed to add server to failover service\n"));
[ # # ][ # # ]
[ # # ]
336 : 0 : return ret;
337 : : }
338 : :
339 : : return EOK;
340 : : }
341 : :
342 : : struct be_resolve_server_state {
343 : : struct tevent_context *ev;
344 : : struct be_ctx *ctx;
345 : :
346 : : struct be_svc_data *svc;
347 : : int attempts;
348 : :
349 : : struct fo_server *srv;
350 : : bool first_try;
351 : : };
352 : :
353 : : struct be_primary_server_ctx {
354 : : struct be_ctx *bctx;
355 : : struct tevent_context *ev;
356 : :
357 : : struct be_svc_data *svc;
358 : : unsigned long timeout;
359 : :
360 : : int attempts;
361 : : };
362 : :
363 : : errno_t be_resolve_server_process(struct tevent_req *subreq,
364 : : struct be_resolve_server_state *state,
365 : : struct tevent_req **new_subreq);
366 : : static void be_primary_server_done(struct tevent_req *subreq);
367 : : static errno_t
368 : : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
369 : : struct tevent_context *ev,
370 : : struct be_ctx *bctx,
371 : : struct be_svc_data *svc,
372 : : const unsigned long timeout_seconds);
373 : :
374 : : static void
375 : 0 : be_primary_server_timeout(struct tevent_context *ev,
376 : : struct tevent_timer *te,
377 : : struct timeval tv, void *pvt)
378 : : {
379 : 0 : struct be_primary_server_ctx *ctx = talloc_get_type(pvt, struct be_primary_server_ctx);
380 : : struct tevent_req *subreq;
381 : :
382 : 0 : ctx->bctx->be_fo->primary_server_handler = NULL;
383 : :
384 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC, ("Looking for primary server!\n"));
[ # # ][ # # ]
[ # # ]
385 : 0 : subreq = fo_resolve_service_send(ctx->bctx, ctx->ev,
386 : : ctx->bctx->be_fo->resolv,
387 : 0 : ctx->bctx->be_fo->fo_ctx,
388 : 0 : ctx->svc->fo_service);
389 [ # # ]: 0 : if (subreq == NULL) {
390 : 0 : return;
391 : : }
392 : 0 : tevent_req_set_callback(subreq, be_primary_server_done, ctx);
393 : : }
394 : :
395 : 0 : static void be_primary_server_done(struct tevent_req *subreq)
396 : : {
397 : : errno_t ret;
398 : : struct be_primary_server_ctx *ctx;
399 : : struct be_resolve_server_state *resolve_state;
400 : : struct tevent_req *new_subreq;
401 : :
402 : 0 : ctx = tevent_req_callback_data(subreq, struct be_primary_server_ctx);
403 : :
404 : 0 : resolve_state = talloc_zero(ctx->bctx, struct be_resolve_server_state);
405 [ # # ]: 0 : if (resolve_state == NULL) {
406 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("talloc_zero() failed\n"));
[ # # ][ # # ]
[ # # ]
407 : : return;
408 : : }
409 : :
410 : 0 : resolve_state->attempts = ctx->attempts;
411 : 0 : resolve_state->ctx = ctx->bctx;
412 : 0 : resolve_state->ev = ctx->ev;
413 : 0 : resolve_state->first_try = true;
414 : 0 : resolve_state->srv = NULL;
415 : 0 : resolve_state->svc = ctx->svc;
416 : :
417 : 0 : ret = be_resolve_server_process(subreq, resolve_state, &new_subreq);
418 : 0 : talloc_free(subreq);
419 [ # # ]: 0 : if (ret == EAGAIN) {
420 : 0 : ctx->attempts++;
421 : 0 : tevent_req_set_callback(new_subreq, be_primary_server_done, ctx);
422 : : return;
423 [ # # ]: 0 : } else if (ret == EIO || (ret == EOK &&
[ # # # # ]
424 : 0 : !fo_is_server_primary(resolve_state->srv))) {
425 : :
426 : : /* Schedule another lookup
427 : : * (either no server could be found or it was not primary)
428 : : */
429 : 0 : ret = be_primary_server_timeout_activate(ctx->bctx, ctx->ev, ctx->bctx,
430 : : ctx->svc, ctx->timeout);
431 [ # # ]: 0 : if (ret != EOK) {
432 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE, ("Could not schedule primary server lookup\n"));
[ # # ][ # # ]
[ # # ]
433 : : }
434 [ # # ]: 0 : } else if (ret == EOK) {
435 : 0 : be_run_reconnect_cb(ctx->bctx);
436 : : }
437 : 0 : talloc_zfree(ctx);
438 : :
439 : : /* If an error occurred just end the routine */
440 : : }
441 : :
442 : : static errno_t
443 : 0 : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
444 : : struct tevent_context *ev,
445 : : struct be_ctx *bctx,
446 : : struct be_svc_data *svc,
447 : : const unsigned long timeout_seconds)
448 : : {
449 : : struct timeval tv;
450 : : struct be_primary_server_ctx *ctx;
451 : 0 : struct be_failover_ctx *fo_ctx = bctx->be_fo;
452 : :
453 [ # # ]: 0 : if (fo_ctx->primary_server_handler != NULL) {
454 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_FUNC, ("The primary server reconnection "
[ # # ][ # # ]
[ # # ]
455 : : "is already scheduled\n"));
456 : : return EOK;
457 : : }
458 : :
459 : 0 : ctx = talloc_zero(mem_ctx, struct be_primary_server_ctx);
460 [ # # ]: 0 : if (ctx == NULL) {
461 : : return ENOMEM;
462 : : }
463 : :
464 : 0 : ctx->bctx = bctx;
465 : 0 : ctx->ev = ev;
466 : 0 : ctx->svc = svc;
467 : 0 : ctx->timeout = timeout_seconds;
468 : :
469 : 0 : tv = tevent_timeval_current();
470 : 0 : tv = tevent_timeval_add(&tv, timeout_seconds, 0);
471 : 0 : fo_ctx->primary_server_handler = tevent_add_timer(ev, bctx, tv,
472 : : be_primary_server_timeout, ctx);
473 [ # # ]: 0 : if (fo_ctx->primary_server_handler == NULL) {
474 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_add_timer failed.\n"));
[ # # ][ # # ]
[ # # ]
475 : 0 : talloc_free(ctx);
476 : : return ENOMEM;
477 : : }
478 : :
479 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_INTERNAL, ("Primary server reactivation timeout set "
[ # # ][ # # ]
[ # # ]
480 : : "to %lu seconds\n", timeout_seconds));
481 : : return EOK;
482 : : }
483 : :
484 : :
485 : : static void be_resolve_server_done(struct tevent_req *subreq);
486 : :
487 : 0 : struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
488 : : struct tevent_context *ev,
489 : : struct be_ctx *ctx,
490 : : const char *service_name,
491 : : bool first_try)
492 : : {
493 : : struct tevent_req *req, *subreq;
494 : : struct be_resolve_server_state *state;
495 : : struct be_svc_data *svc;
496 : :
497 : 0 : req = tevent_req_create(memctx, &state, struct be_resolve_server_state);
498 [ # # ]: 0 : if (!req) return NULL;
499 : :
500 : 0 : state->ev = ev;
501 : 0 : state->ctx = ctx;
502 : :
503 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
504 [ # # ]: 0 : if (NULL == svc) {
505 : 0 : tevent_req_error(req, EINVAL);
506 : 0 : tevent_req_post(req, ev);
507 : : return req;
508 : : }
509 : :
510 : 0 : state->svc = svc;
511 : 0 : state->attempts = 0;
512 : 0 : state->first_try = first_try;
513 : :
514 : 0 : subreq = fo_resolve_service_send(state, ev,
515 : : ctx->be_fo->resolv,
516 : 0 : ctx->be_fo->fo_ctx,
517 : : svc->fo_service);
518 [ # # ]: 0 : if (!subreq) {
519 : 0 : talloc_zfree(req);
520 : : return NULL;
521 : : }
522 : 0 : tevent_req_set_callback(subreq, be_resolve_server_done, req);
523 : :
524 : : return req;
525 : : }
526 : :
527 : 0 : static void be_resolve_server_done(struct tevent_req *subreq)
528 : : {
529 : : struct tevent_req *new_subreq;
530 : 0 : struct tevent_req *req = tevent_req_callback_data(subreq,
531 : : struct tevent_req);
532 : 0 : struct be_resolve_server_state *state = tevent_req_data(req,
533 : : struct be_resolve_server_state);
534 : : int ret;
535 : :
536 : 0 : ret = be_resolve_server_process(subreq, state, &new_subreq);
537 : 0 : talloc_zfree(subreq);
538 [ # # ]: 0 : if (ret == EAGAIN) {
539 : 0 : tevent_req_set_callback(new_subreq, be_resolve_server_done, req);
540 : : return;
541 [ # # ]: 0 : } else if (ret != EOK) {
542 : : goto fail;
543 : : }
544 : :
545 [ # # ]: 0 : if (!fo_is_server_primary(state->srv)) {
546 : : /* FIXME: make the timeout configurable */
547 : 0 : ret = be_primary_server_timeout_activate(state->ctx, state->ev,
548 : : state->ctx, state->svc,
549 : : 30);
550 [ # # ]: 0 : if (ret != EOK) {
551 : : goto fail;
552 : : }
553 : : }
554 : :
555 : 0 : tevent_req_done(req);
556 : : return;
557 : :
558 : : fail:
559 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_LIBS, ("Server resolution failed: %d\n", ret));
[ # # ][ # # ]
[ # # ]
560 : 0 : state->svc->first_resolved = NULL;
561 : 0 : tevent_req_error(req, ret);
562 : : }
563 : :
564 : 0 : errno_t be_resolve_server_process(struct tevent_req *subreq,
565 : : struct be_resolve_server_state *state,
566 : : struct tevent_req **new_subreq)
567 : : {
568 : : errno_t ret;
569 : : time_t srv_status_change;
570 : : struct be_svc_callback *callback;
571 : :
572 : 0 : ret = fo_resolve_service_recv(subreq, &state->srv);
573 [ # # # ]: 0 : switch (ret) {
574 : : case EOK:
575 [ # # ]: 0 : if (!state->srv) {
576 : : return EFAULT;
577 : : }
578 : : break;
579 : :
580 : : case ENOENT:
581 : : /* all servers have been tried and none
582 : : * was found good, go offline */
583 : : return EIO;
584 : :
585 : : default:
586 : : /* mark server as bad and retry */
587 [ # # ]: 0 : if (!state->srv) {
588 : : return EFAULT;
589 : : }
590 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_MINOR_FAILURE,
[ # # ][ # # ]
[ # # ]
591 : : ("Couldn't resolve server (%s), resolver returned (%d)\n",
592 : : fo_get_server_str_name(state->srv), ret));
593 : :
594 : 0 : state->attempts++;
595 [ # # ]: 0 : if (state->attempts >= 10) {
596 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE, ("Failed to find a server after 10 attempts\n"));
[ # # ][ # # ]
[ # # ]
597 : : return EIO;
598 : : }
599 : :
600 : : /* now try next one */
601 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_LIBS, ("Trying with the next one!\n"));
[ # # ][ # # ]
[ # # ]
602 : 0 : subreq = fo_resolve_service_send(state, state->ev,
603 : : state->ctx->be_fo->resolv,
604 : 0 : state->ctx->be_fo->fo_ctx,
605 : 0 : state->svc->fo_service);
606 [ # # ]: 0 : if (!subreq) {
607 : : return ENOMEM;
608 : : }
609 : :
610 [ # # ]: 0 : if (new_subreq) {
611 : 0 : *new_subreq = subreq;
612 : : }
613 : :
614 : : return EAGAIN;
615 : : }
616 : :
617 : : /* all fine we got the server */
618 [ # # ][ # # ]: 0 : if (state->svc->first_resolved == NULL || state->first_try == true) {
619 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_TRACE_LIBS, ("Saving the first resolved server\n"));
[ # # ][ # # ]
[ # # ]
620 : 0 : state->svc->first_resolved = state->srv;
621 [ # # ]: 0 : } else if (state->svc->first_resolved == state->srv) {
622 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
623 : : ("The fail over cycled through all available servers\n"));
624 : : return ENOENT;
625 : : }
626 : :
627 [ # # ][ # # ]: 0 : if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) {
628 : : struct resolv_hostent *srvaddr;
629 : : char ipaddr[128];
630 : 0 : srvaddr = fo_get_server_hostent(state->srv);
631 [ # # ]: 0 : if (!srvaddr) {
632 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_CRIT_FAILURE,
[ # # ][ # # ]
[ # # ]
633 : : ("FATAL: No hostent available for server (%s)\n",
634 : : fo_get_server_str_name(state->srv)));
635 : : return EFAULT;
636 : : }
637 : :
638 : 0 : inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr,
639 : : ipaddr, 128);
640 : :
641 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_FUNC_DATA, ("Found address for server %s: [%s] TTL %d\n",
[ # # ][ # # ]
[ # # ]
642 : : fo_get_server_str_name(state->srv), ipaddr,
643 : : srvaddr->addr_list[0]->ttl));
644 : : }
645 : :
646 : 0 : srv_status_change = fo_get_server_hostname_last_change(state->srv);
647 : :
648 : : /* now call all svc callbacks if server changed or if it is explicitly
649 : : * requested or if the server is the same but changed status since last time*/
650 [ # # ][ # # ]: 0 : if (state->srv != state->svc->last_good_srv ||
651 [ # # ]: 0 : state->svc->run_callbacks ||
652 : 0 : srv_status_change > state->svc->last_status_change) {
653 : 0 : state->svc->last_good_srv = state->srv;
654 : 0 : state->svc->last_status_change = srv_status_change;
655 : 0 : state->svc->run_callbacks = false;
656 : :
657 [ # # ]: 0 : DLIST_FOR_EACH(callback, state->svc->callbacks) {
658 : 0 : callback->fn(callback->private_data, state->srv);
659 : : }
660 : : }
661 : :
662 : : return EOK;
663 : : }
664 : :
665 : 0 : int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv)
666 : : {
667 : 0 : struct be_resolve_server_state *state = tevent_req_data(req,
668 : : struct be_resolve_server_state);
669 : :
670 [ # # ][ # # ]: 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
671 : :
672 [ # # ]: 0 : if (srv) {
673 : 0 : *srv = state->srv;
674 : : }
675 : :
676 : : return EOK;
677 : : }
678 : :
679 : 0 : void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name)
680 : : {
681 : : struct be_svc_data *svc;
682 : :
683 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
684 [ # # ]: 0 : if (svc) {
685 : 0 : fo_try_next_server(svc->fo_service);
686 : : }
687 : 0 : }
688 : :
689 : 0 : int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
690 : : const char *service_name)
691 : : {
692 : : struct be_svc_data *svc;
693 : :
694 : 0 : svc = be_fo_find_svc_data(ctx, service_name);
695 [ # # ]: 0 : if (NULL == svc) {
696 : : return ENOENT;
697 : : }
698 : :
699 : 0 : svc->run_callbacks = true;
700 : :
701 : 0 : return EOK;
702 : : }
703 : :
704 : 0 : void reset_fo(struct be_ctx *be_ctx)
705 : : {
706 : 0 : fo_reset_services(be_ctx->be_fo->fo_ctx);
707 : 0 : }
708 : :
709 : 0 : void be_fo_set_port_status(struct be_ctx *ctx,
710 : : const char *service_name,
711 : : struct fo_server *server,
712 : : enum port_status status)
713 : : {
714 : : struct be_svc_data *be_svc;
715 : :
716 : 0 : be_svc = be_fo_find_svc_data(ctx, service_name);
717 [ # # ]: 0 : if (be_svc == NULL) {
718 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
719 : : ("No service associated with name %s\n", service_name));
720 : : return;
721 : : }
722 : :
723 [ # # ]: 0 : if (!fo_svc_has_server(be_svc->fo_service, server)) {
724 [ # # ][ # # ]: 0 : DEBUG(SSSDBG_OP_FAILURE,
[ # # ][ # # ]
[ # # ]
725 : : ("The server %p is not valid anymore, cannot set its status\n"));
726 : : return;
727 : : }
728 : :
729 : : /* Now we know that the server is valid */
730 : 0 : fo_set_port_status(server, status);
731 : :
732 [ # # ]: 0 : if (status == PORT_WORKING) {
733 : : /* We were successful in connecting to the server. Cycle through all
734 : : * available servers next time */
735 : 0 : be_svc->first_resolved = NULL;
736 : : }
737 : 0 : }
|