LCOV - code coverage report
Current view: top level - providers - data_provider_fo.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 96 365 26.3 %
Date: 2015-10-19 Functions: 12 27 44.4 %

          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 be_resolv_ctx *be_res;
      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          12 : int be_fo_is_srv_identifier(const char *server)
      63             : {
      64          12 :     return server && strcasecmp(server, BE_SRV_IDENTIFIER) == 0;
      65             : }
      66             : 
      67           7 : static int be_fo_get_options(struct be_ctx *ctx,
      68             :                              struct fo_options *opts)
      69             : {
      70           7 :     opts->service_resolv_timeout = dp_opt_get_int(ctx->be_res->opts,
      71             :                                                   DP_RES_OPT_RESOLVER_TIMEOUT);
      72           7 :     opts->retry_timeout = 30;
      73           7 :     opts->srv_retry_neg_timeout = 15;
      74           7 :     opts->family_order = ctx->be_res->family_order;
      75             : 
      76           7 :     return EOK;
      77             : }
      78             : 
      79           7 : int be_init_failover(struct be_ctx *ctx)
      80             : {
      81             :     int ret;
      82             :     struct fo_options fopts;
      83             : 
      84           7 :     if (ctx->be_fo != NULL) {
      85           0 :         return EOK;
      86             :     }
      87             : 
      88           7 :     ctx->be_fo = talloc_zero(ctx, struct be_failover_ctx);
      89           7 :     if (!ctx->be_fo) {
      90           0 :         return ENOMEM;
      91             :     }
      92             : 
      93           7 :     ret = be_res_init(ctx);
      94           7 :     if (ret != EOK) {
      95           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      96             :               "fatal error initializing resolver context\n");
      97           0 :         talloc_zfree(ctx->be_fo);
      98           0 :         return ret;
      99             :     }
     100           7 :     ctx->be_fo->be_res = ctx->be_res;
     101             : 
     102           7 :     ret = be_fo_get_options(ctx, &fopts);
     103           7 :     if (ret != EOK) {
     104           0 :         talloc_zfree(ctx->be_fo);
     105           0 :         return ret;
     106             :     }
     107             : 
     108           7 :     ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, &fopts);
     109           7 :     if (!ctx->be_fo->fo_ctx) {
     110           0 :         talloc_zfree(ctx->be_fo);
     111           0 :         return ENOMEM;
     112             :     }
     113             : 
     114           7 :     return EOK;
     115             : }
     116             : 
     117          24 : static int be_svc_data_destroy(void *memptr)
     118             : {
     119             :     struct be_svc_data *svc;
     120             : 
     121          24 :     svc = talloc_get_type(memptr, struct be_svc_data);
     122             : 
     123          48 :     while (svc->callbacks) {
     124             :         /* callbacks removes themselves from the list,
     125             :          * so this while will freem them all and then terminate */
     126           0 :         talloc_free(svc->callbacks);
     127             :     }
     128             : 
     129          24 :     return 0;
     130             : }
     131             : 
     132             : /*
     133             :  * Find registered be_svc_data by service name.
     134             :  */
     135          72 : static struct be_svc_data *be_fo_find_svc_data(struct be_ctx *ctx,
     136             :                                                const char *service_name)
     137             : {
     138             :     struct be_svc_data *svc;
     139             : 
     140          72 :     if (!ctx || !ctx->be_fo) {
     141           0 :         return 0;
     142             :     }
     143             : 
     144         132 :     DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
     145         108 :         if (strcmp(svc->name, service_name) == 0) {
     146          48 :             return svc;
     147             :         }
     148             :     }
     149             : 
     150          24 :     return 0;
     151             : }
     152             : 
     153          24 : int be_fo_add_service(struct be_ctx *ctx, const char *service_name,
     154             :                       datacmp_fn user_data_cmp)
     155             : {
     156             :     struct fo_service *service;
     157             :     struct be_svc_data *svc;
     158             :     int ret;
     159             : 
     160          24 :     svc = be_fo_find_svc_data(ctx, service_name);
     161          24 :     if (svc) {
     162           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Failover service already initialized!\n");
     163             :         /* we already have a service up and configured,
     164             :          * can happen when using both id and auth provider
     165             :          */
     166           0 :         return EOK;
     167             :     }
     168             : 
     169             :     /* if not in the be service list, try to create new one */
     170             : 
     171          24 :     ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, user_data_cmp,
     172             :                          &service);
     173          24 :     if (ret != EOK && ret != EEXIST) {
     174           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create failover service!\n");
     175           0 :         return ret;
     176             :     }
     177             : 
     178          24 :     svc = talloc_zero(ctx->be_fo, struct be_svc_data);
     179          24 :     if (!svc) {
     180           0 :         return ENOMEM;
     181             :     }
     182          24 :     talloc_set_destructor((TALLOC_CTX *)svc, be_svc_data_destroy);
     183             : 
     184          24 :     svc->name = talloc_strdup(svc, service_name);
     185          24 :     if (!svc->name) {
     186           0 :         talloc_zfree(svc);
     187           0 :         return ENOMEM;
     188             :     }
     189          24 :     svc->fo_service = service;
     190             : 
     191          24 :     DLIST_ADD(ctx->be_fo->svcs, svc);
     192             : 
     193          24 :     return EOK;
     194             : }
     195             : 
     196          24 : static int be_svc_callback_destroy(void *memptr)
     197             : {
     198             :     struct be_svc_callback *callback;
     199             : 
     200          24 :     callback = talloc_get_type(memptr, struct be_svc_callback);
     201             : 
     202          24 :     if (callback->svc) {
     203          24 :         DLIST_REMOVE(callback->svc->callbacks, callback);
     204             :     }
     205             : 
     206          24 :     return 0;
     207             : }
     208             : 
     209          24 : int be_fo_service_add_callback(TALLOC_CTX *memctx,
     210             :                                struct be_ctx *ctx, const char *service_name,
     211             :                                be_svc_callback_fn_t *fn, void *private_data)
     212             : {
     213             :     struct be_svc_callback *callback;
     214             :     struct be_svc_data *svc;
     215             : 
     216          24 :     svc = be_fo_find_svc_data(ctx, service_name);
     217          24 :     if (NULL == svc) {
     218           0 :         return ENOENT;
     219             :     }
     220             : 
     221          24 :     callback = talloc_zero(memctx, struct be_svc_callback);
     222          24 :     if (!callback) {
     223           0 :         return ENOMEM;
     224             :     }
     225          24 :     talloc_set_destructor((TALLOC_CTX *)callback, be_svc_callback_destroy);
     226             : 
     227          24 :     callback->svc = svc;
     228          24 :     callback->fn = fn;
     229          24 :     callback->private_data = private_data;
     230             : 
     231          24 :     DLIST_ADD(svc->callbacks, callback);
     232             : 
     233          24 :     return EOK;
     234             : }
     235             : 
     236          12 : void be_fo_set_srv_lookup_plugin(struct be_ctx *ctx,
     237             :                                  fo_srv_lookup_plugin_send_t send_fn,
     238             :                                  fo_srv_lookup_plugin_recv_t recv_fn,
     239             :                                  void *pvt,
     240             :                                  const char *plugin_name)
     241             : {
     242             :     bool bret;
     243             : 
     244          12 :     DEBUG(SSSDBG_TRACE_FUNC, "Trying to set SRV lookup plugin to %s\n",
     245             :                               plugin_name);
     246             : 
     247          12 :     bret = fo_set_srv_lookup_plugin(ctx->be_fo->fo_ctx, send_fn, recv_fn, pvt);
     248          12 :     if (bret) {
     249           6 :         DEBUG(SSSDBG_TRACE_FUNC, "SRV lookup plugin is now %s\n",
     250             :                                   plugin_name);
     251             :     } else {
     252           6 :         DEBUG(SSSDBG_MINOR_FAILURE, "Unable to set SRV lookup plugin, "
     253             :               "another plugin may be already in place\n");
     254             :     }
     255          12 : }
     256             : 
     257           0 : errno_t be_fo_set_dns_srv_lookup_plugin(struct be_ctx *be_ctx,
     258             :                                         const char *hostname)
     259             : {
     260           0 :     struct fo_resolve_srv_dns_ctx *srv_ctx = NULL;
     261             :     char resolved_hostname[HOST_NAME_MAX + 1];
     262             :     errno_t ret;
     263             : 
     264           0 :     if (hostname == NULL) {
     265           0 :         ret = gethostname(resolved_hostname, HOST_NAME_MAX);
     266           0 :         if (ret != EOK) {
     267           0 :             ret = errno;
     268           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     269             :                   "gethostname() failed: [%d]: %s\n", ret, strerror(ret));
     270           0 :             return ret;
     271             :         }
     272           0 :         resolved_hostname[HOST_NAME_MAX] = '\0';
     273           0 :         hostname = resolved_hostname;
     274             :     }
     275             : 
     276           0 :     srv_ctx = fo_resolve_srv_dns_ctx_init(be_ctx, be_ctx->be_res->resolv,
     277           0 :                                           be_ctx->be_res->family_order,
     278             :                                           default_host_dbs, hostname,
     279           0 :                                           be_ctx->domain->name);
     280           0 :     if (srv_ctx == NULL) {
     281           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
     282           0 :         return ENOMEM;
     283             :     }
     284             : 
     285           0 :     be_fo_set_srv_lookup_plugin(be_ctx, fo_resolve_srv_dns_send,
     286             :                                 fo_resolve_srv_dns_recv, srv_ctx, "DNS");
     287             : 
     288           0 :     return EOK;
     289             : }
     290             : 
     291          24 : int be_fo_add_srv_server(struct be_ctx *ctx,
     292             :                          const char *service_name,
     293             :                          const char *query_service,
     294             :                          const char *default_discovery_domain,
     295             :                          enum be_fo_protocol proto,
     296             :                          bool proto_fallback, void *user_data)
     297             : {
     298             :     struct be_svc_data *svc;
     299             :     const char *domain;
     300             :     int ret;
     301             :     int i;
     302             : 
     303          24 :     svc = be_fo_find_svc_data(ctx, service_name);
     304          24 :     if (NULL == svc) {
     305           0 :         return ENOENT;
     306             :     }
     307             : 
     308          24 :     domain = dp_opt_get_string(ctx->be_res->opts, DP_RES_OPT_DNS_DOMAIN);
     309          24 :     if (!domain) {
     310          24 :         domain = default_discovery_domain;
     311             :     }
     312             : 
     313             :     /* Add the first protocol as the primary lookup */
     314          48 :     ret = fo_add_srv_server(svc->fo_service, query_service,
     315          24 :                             domain, ctx->domain->name,
     316             :                             proto_table[proto], user_data);
     317          24 :     if (ret && ret != EEXIST) {
     318           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     319             :               "Failed to add SRV lookup reference to failover service\n");
     320           0 :         return ret;
     321             :     }
     322             : 
     323          24 :     if (proto_fallback) {
     324           0 :         i = (proto + 1) % BE_FO_PROTO_SENTINEL;
     325             :         /* All the rest as fallback */
     326           0 :         while (i != proto) {
     327           0 :             ret = fo_add_srv_server(svc->fo_service, query_service,
     328           0 :                                     domain, ctx->domain->name,
     329             :                                     proto_table[i], user_data);
     330           0 :             if (ret && ret != EEXIST) {
     331           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     332             :                       "Failed to add SRV lookup reference to failover service\n");
     333           0 :                 return ret;
     334             :             }
     335             : 
     336           0 :             i = (i + 1) % BE_FO_PROTO_SENTINEL;
     337             :         }
     338             :     }
     339             : 
     340          24 :     return EOK;
     341             : }
     342             : 
     343           0 : int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
     344             : {
     345             :     struct be_svc_data *svc_data;
     346             : 
     347           0 :     svc_data = be_fo_find_svc_data(ctx, service_name);
     348           0 :     if (!svc_data) {
     349           0 :         return 0;
     350             :     }
     351             : 
     352           0 :     return fo_get_server_count(svc_data->fo_service);
     353             : }
     354             : 
     355           0 : int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
     356             :                      const char *server, int port, void *user_data,
     357             :                      bool primary)
     358             : {
     359             :     struct be_svc_data *svc;
     360             :     int ret;
     361             : 
     362           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     363           0 :     if (NULL == svc) {
     364           0 :         return ENOENT;
     365             :     }
     366             : 
     367           0 :     ret = fo_add_server(svc->fo_service, server, port,
     368             :                         user_data, primary);
     369           0 :     if (ret && ret != EEXIST) {
     370           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     371             :               "Failed to add server to failover service\n");
     372           0 :         return ret;
     373             :     }
     374             : 
     375           0 :     return EOK;
     376             : }
     377             : 
     378             : struct be_resolve_server_state {
     379             :     struct tevent_context *ev;
     380             :     struct be_ctx *ctx;
     381             : 
     382             :     struct be_svc_data *svc;
     383             :     int attempts;
     384             : 
     385             :     struct fo_server *srv;
     386             :     bool first_try;
     387             : };
     388             : 
     389             : struct be_primary_server_ctx {
     390             :     struct be_ctx *bctx;
     391             :     struct tevent_context *ev;
     392             : 
     393             :     struct be_svc_data *svc;
     394             :     unsigned long timeout;
     395             : 
     396             :     int attempts;
     397             : };
     398             : 
     399             : errno_t be_resolve_server_process(struct tevent_req *subreq,
     400             :                                   struct be_resolve_server_state *state,
     401             :                                   struct tevent_req **new_subreq);
     402             : static void be_primary_server_done(struct tevent_req *subreq);
     403             : static errno_t
     404             : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
     405             :                                    struct tevent_context *ev,
     406             :                                    struct be_ctx *bctx,
     407             :                                    struct be_svc_data *svc,
     408             :                                    const unsigned long timeout_seconds);
     409             : 
     410             : static void
     411           0 : be_primary_server_timeout(struct tevent_context *ev,
     412             :                           struct tevent_timer *te,
     413             :                           struct timeval tv, void *pvt)
     414             : {
     415           0 :     struct be_primary_server_ctx *ctx = talloc_get_type(pvt, struct be_primary_server_ctx);
     416             :     struct tevent_req *subreq;
     417             : 
     418           0 :     ctx->bctx->be_fo->primary_server_handler = NULL;
     419             : 
     420           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Looking for primary server!\n");
     421           0 :     subreq = fo_resolve_service_send(ctx->bctx, ctx->ev,
     422           0 :                                      ctx->bctx->be_fo->be_res->resolv,
     423           0 :                                      ctx->bctx->be_fo->fo_ctx,
     424           0 :                                      ctx->svc->fo_service);
     425           0 :     if (subreq == NULL) {
     426           0 :         return;
     427             :     }
     428           0 :     tevent_req_set_callback(subreq, be_primary_server_done, ctx);
     429             : }
     430             : 
     431           0 : static void be_primary_server_done(struct tevent_req *subreq)
     432             : {
     433             :     errno_t ret;
     434             :     struct be_primary_server_ctx *ctx;
     435             :     struct be_resolve_server_state *resolve_state;
     436             :     struct tevent_req *new_subreq;
     437             : 
     438           0 :     ctx = tevent_req_callback_data(subreq, struct be_primary_server_ctx);
     439             : 
     440           0 :     resolve_state = talloc_zero(ctx->bctx, struct be_resolve_server_state);
     441           0 :     if (resolve_state == NULL) {
     442           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
     443           0 :         return;
     444             :     }
     445             : 
     446           0 :     resolve_state->attempts = ctx->attempts;
     447           0 :     resolve_state->ctx = ctx->bctx;
     448           0 :     resolve_state->ev = ctx->ev;
     449           0 :     resolve_state->first_try = true;
     450           0 :     resolve_state->srv = NULL;
     451           0 :     resolve_state->svc = ctx->svc;
     452             : 
     453           0 :     ret = be_resolve_server_process(subreq, resolve_state, &new_subreq);
     454           0 :     talloc_free(subreq);
     455           0 :     if (ret == EAGAIN) {
     456           0 :         ctx->attempts++;
     457           0 :         tevent_req_set_callback(new_subreq, be_primary_server_done, ctx);
     458           0 :         return;
     459           0 :     } else if (ret == EIO || (ret == EOK &&
     460           0 :         !fo_is_server_primary(resolve_state->srv))) {
     461             : 
     462             :         /* Schedule another lookup
     463             :          * (either no server could be found or it was not primary)
     464             :          */
     465           0 :         ret = be_primary_server_timeout_activate(ctx->bctx, ctx->ev, ctx->bctx,
     466             :                                                  ctx->svc, ctx->timeout);
     467           0 :         if (ret != EOK) {
     468           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Could not schedule primary server lookup\n");
     469             :         }
     470           0 :     } else if (ret == EOK) {
     471           0 :         be_run_reconnect_cb(ctx->bctx);
     472             :     }
     473           0 :     talloc_zfree(ctx);
     474             : 
     475             :     /* If an error occurred just end the routine */
     476             : }
     477             : 
     478             : static errno_t
     479           0 : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
     480             :                                    struct tevent_context *ev,
     481             :                                    struct be_ctx *bctx,
     482             :                                    struct be_svc_data *svc,
     483             :                                    const unsigned long timeout_seconds)
     484             : {
     485             :     struct timeval tv;
     486             :     struct be_primary_server_ctx *ctx;
     487           0 :     struct be_failover_ctx *fo_ctx = bctx->be_fo;
     488             : 
     489           0 :     if (fo_ctx->primary_server_handler != NULL) {
     490           0 :         DEBUG(SSSDBG_TRACE_FUNC, "The primary server reconnection "
     491             :                                   "is already scheduled\n");
     492           0 :         return EOK;
     493             :     }
     494             : 
     495           0 :     ctx = talloc_zero(mem_ctx, struct be_primary_server_ctx);
     496           0 :     if (ctx == NULL) {
     497           0 :         return ENOMEM;
     498             :     }
     499             : 
     500           0 :     ctx->bctx = bctx;
     501           0 :     ctx->ev = ev;
     502           0 :     ctx->svc = svc;
     503           0 :     ctx->timeout = timeout_seconds;
     504             : 
     505           0 :     tv = tevent_timeval_current();
     506           0 :     tv = tevent_timeval_add(&tv, timeout_seconds, 0);
     507           0 :     fo_ctx->primary_server_handler = tevent_add_timer(ev, bctx, tv,
     508             :                                           be_primary_server_timeout, ctx);
     509           0 :     if (fo_ctx->primary_server_handler == NULL) {
     510           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     511           0 :         talloc_free(ctx);
     512           0 :         return ENOMEM;
     513             :     }
     514             : 
     515           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Primary server reactivation timeout set "
     516             :                                   "to %lu seconds\n", timeout_seconds);
     517           0 :     return EOK;
     518             : }
     519             : 
     520             : 
     521             : static void be_resolve_server_done(struct tevent_req *subreq);
     522             : 
     523           0 : struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
     524             :                                           struct tevent_context *ev,
     525             :                                           struct be_ctx *ctx,
     526             :                                           const char *service_name,
     527             :                                           bool first_try)
     528             : {
     529             :     struct tevent_req *req, *subreq;
     530             :     struct be_resolve_server_state *state;
     531             :     struct be_svc_data *svc;
     532             : 
     533           0 :     req = tevent_req_create(memctx, &state, struct be_resolve_server_state);
     534           0 :     if (!req) return NULL;
     535             : 
     536           0 :     state->ev = ev;
     537           0 :     state->ctx = ctx;
     538             : 
     539           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     540           0 :     if (NULL == svc) {
     541           0 :         tevent_req_error(req, EINVAL);
     542           0 :         tevent_req_post(req, ev);
     543           0 :         return req;
     544             :     }
     545             : 
     546           0 :     state->svc = svc;
     547           0 :     state->attempts = 0;
     548           0 :     state->first_try = first_try;
     549             : 
     550           0 :     subreq = fo_resolve_service_send(state, ev,
     551           0 :                                      ctx->be_fo->be_res->resolv,
     552           0 :                                      ctx->be_fo->fo_ctx,
     553             :                                      svc->fo_service);
     554           0 :     if (!subreq) {
     555           0 :         talloc_zfree(req);
     556           0 :         return NULL;
     557             :     }
     558           0 :     tevent_req_set_callback(subreq, be_resolve_server_done, req);
     559             : 
     560           0 :     return req;
     561             : }
     562             : 
     563           0 : static void be_resolve_server_done(struct tevent_req *subreq)
     564             : {
     565             :     struct tevent_req *new_subreq;
     566           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     567             :                                                       struct tevent_req);
     568           0 :     struct be_resolve_server_state *state = tevent_req_data(req,
     569             :                                              struct be_resolve_server_state);
     570           0 :     time_t timeout = fo_get_service_retry_timeout(state->svc->fo_service) + 1;
     571             :     int ret;
     572             : 
     573           0 :     ret = be_resolve_server_process(subreq, state, &new_subreq);
     574           0 :     talloc_zfree(subreq);
     575           0 :     if (ret == EAGAIN) {
     576           0 :         tevent_req_set_callback(new_subreq, be_resolve_server_done, req);
     577           0 :         return;
     578           0 :     } else if (ret != EOK) {
     579           0 :         goto fail;
     580             :     }
     581             : 
     582           0 :     if (!fo_is_server_primary(state->srv)) {
     583             :         /* FIXME: make the timeout configurable */
     584           0 :         ret = be_primary_server_timeout_activate(state->ctx, state->ev,
     585             :                                                  state->ctx, state->svc,
     586             :                                                  timeout);
     587           0 :         if (ret != EOK) {
     588           0 :             goto fail;
     589             :         }
     590             :     }
     591             : 
     592           0 :     tevent_req_done(req);
     593           0 :     return;
     594             : 
     595             : fail:
     596           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Server resolution failed: %d\n", ret);
     597           0 :     state->svc->first_resolved = NULL;
     598           0 :     tevent_req_error(req, ret);
     599             : }
     600             : 
     601           0 : errno_t be_resolve_server_process(struct tevent_req *subreq,
     602             :                                   struct be_resolve_server_state *state,
     603             :                                   struct tevent_req **new_subreq)
     604             : {
     605             :     errno_t ret;
     606             :     time_t srv_status_change;
     607             :     struct be_svc_callback *callback;
     608             : 
     609           0 :     ret = fo_resolve_service_recv(subreq, &state->srv);
     610           0 :     switch (ret) {
     611             :     case EOK:
     612           0 :         if (!state->srv) {
     613           0 :             return EFAULT;
     614             :         }
     615           0 :         break;
     616             : 
     617             :     case ENOENT:
     618             :         /* all servers have been tried and none
     619             :          * was found good, go offline */
     620           0 :         return EIO;
     621             : 
     622             :     default:
     623             :         /* mark server as bad and retry */
     624           0 :         if (!state->srv) {
     625           0 :             return EFAULT;
     626             :         }
     627           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     628             :               "Couldn't resolve server (%s), resolver returned (%d)\n",
     629             :               fo_get_server_str_name(state->srv), ret);
     630             : 
     631           0 :         state->attempts++;
     632           0 :         if (state->attempts >= 10) {
     633           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to find a server after 10 attempts\n");
     634           0 :             return EIO;
     635             :         }
     636             : 
     637             :         /* now try next one */
     638           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Trying with the next one!\n");
     639           0 :         subreq = fo_resolve_service_send(state, state->ev,
     640           0 :                                          state->ctx->be_fo->be_res->resolv,
     641           0 :                                          state->ctx->be_fo->fo_ctx,
     642           0 :                                          state->svc->fo_service);
     643           0 :         if (!subreq) {
     644           0 :             return ENOMEM;
     645             :         }
     646             : 
     647           0 :         if (new_subreq) {
     648           0 :             *new_subreq = subreq;
     649             :         }
     650             : 
     651           0 :         return EAGAIN;
     652             :     }
     653             : 
     654             :     /* all fine we got the server */
     655           0 :     if (state->svc->first_resolved == NULL || state->first_try == true) {
     656           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Saving the first resolved server\n");
     657           0 :         state->svc->first_resolved = state->srv;
     658           0 :     } else if (state->svc->first_resolved == state->srv) {
     659           0 :         DEBUG(SSSDBG_OP_FAILURE,
     660             :               "The fail over cycled through all available servers\n");
     661           0 :         return ENOENT;
     662             :     }
     663             : 
     664           0 :     if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) {
     665             :         struct resolv_hostent *srvaddr;
     666             :         char ipaddr[128];
     667           0 :         srvaddr = fo_get_server_hostent(state->srv);
     668           0 :         if (!srvaddr) {
     669           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     670             :                   "FATAL: No hostent available for server (%s)\n",
     671             :                   fo_get_server_str_name(state->srv));
     672           0 :             return EFAULT;
     673             :         }
     674             : 
     675           0 :         inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr,
     676             :                   ipaddr, 128);
     677             : 
     678           0 :         DEBUG(SSSDBG_FUNC_DATA, "Found address for server %s: [%s] TTL %d\n",
     679             :               fo_get_server_str_name(state->srv), ipaddr,
     680             :               srvaddr->addr_list[0]->ttl);
     681             :     }
     682             : 
     683           0 :     srv_status_change = fo_get_server_hostname_last_change(state->srv);
     684             : 
     685             :     /* now call all svc callbacks if server changed or if it is explicitly
     686             :      * requested or if the server is the same but changed status since last time*/
     687           0 :     if (state->srv != state->svc->last_good_srv ||
     688           0 :         state->svc->run_callbacks ||
     689           0 :         srv_status_change > state->svc->last_status_change) {
     690           0 :         state->svc->last_good_srv = state->srv;
     691           0 :         state->svc->last_status_change = srv_status_change;
     692           0 :         state->svc->run_callbacks = false;
     693             : 
     694           0 :         DLIST_FOR_EACH(callback, state->svc->callbacks) {
     695           0 :             callback->fn(callback->private_data, state->srv);
     696             :         }
     697             :     }
     698             : 
     699           0 :     return EOK;
     700             : }
     701             : 
     702           0 : int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv)
     703             : {
     704           0 :     struct be_resolve_server_state *state = tevent_req_data(req,
     705             :                                              struct be_resolve_server_state);
     706             : 
     707           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     708             : 
     709           0 :     if (srv) {
     710           0 :         *srv = state->srv;
     711             :     }
     712             : 
     713           0 :     return EOK;
     714             : }
     715             : 
     716           0 : void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name)
     717             : {
     718             :     struct be_svc_data *svc;
     719             : 
     720           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     721           0 :     if (svc) {
     722           0 :         fo_try_next_server(svc->fo_service);
     723             :     }
     724           0 : }
     725             : 
     726           0 : int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
     727             :                                         const char *service_name)
     728             : {
     729             :     struct be_svc_data *svc;
     730             : 
     731           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     732           0 :     if (NULL == svc) {
     733           0 :         return ENOENT;
     734             :     }
     735             : 
     736           0 :     svc->run_callbacks = true;
     737             : 
     738           0 :     return EOK;
     739             : }
     740             : 
     741           0 : void reset_fo(struct be_ctx *be_ctx)
     742             : {
     743           0 :     fo_reset_services(be_ctx->be_fo->fo_ctx);
     744           0 : }
     745             : 
     746           0 : void be_fo_reset_svc(struct be_ctx *be_ctx,
     747             :                      const char *svc_name)
     748             : {
     749             :     struct fo_service *service;
     750             :     int ret;
     751             : 
     752           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     753             :           "Resetting all servers in service %s\n", svc_name);
     754             : 
     755           0 :     ret = fo_get_service(be_ctx->be_fo->fo_ctx, svc_name, &service);
     756           0 :     if (ret != EOK) {
     757           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     758             :               "Cannot retrieve service [%s]\n", svc_name);
     759           0 :         return;
     760             :     }
     761             : 
     762           0 :     fo_reset_servers(service);
     763             : }
     764             : 
     765           0 : void _be_fo_set_port_status(struct be_ctx *ctx,
     766             :                             const char *service_name,
     767             :                             struct fo_server *server,
     768             :                             enum port_status status,
     769             :                             int line,
     770             :                             const char *file,
     771             :                             const char *function)
     772             : {
     773             :     struct be_svc_data *be_svc;
     774             : 
     775             :     /* Print debug info */
     776           0 :     switch (status) {
     777             :     case PORT_NEUTRAL:
     778           0 :         DEBUG(SSSDBG_BE_FO,
     779             :               "Setting status: PORT_NEUTRAL. Called from: %s: %s: %d\n",
     780             :               file, function, line);
     781           0 :         break;
     782             :     case PORT_WORKING:
     783           0 :         DEBUG(SSSDBG_BE_FO,
     784             :               "Setting status: PORT_WORKING. Called from: %s: %s: %d\n",
     785             :               file, function, line);
     786           0 :         break;
     787             :     case PORT_NOT_WORKING:
     788           0 :         DEBUG(SSSDBG_BE_FO,
     789             :               "Setting status: PORT_NOT_WORKING. Called from: %s: %s: %d\n",
     790             :               file, function, line);
     791           0 :         break;
     792             :     }
     793             : 
     794           0 :     be_svc = be_fo_find_svc_data(ctx, service_name);
     795           0 :     if (be_svc == NULL) {
     796           0 :         DEBUG(SSSDBG_OP_FAILURE,
     797             :               "No service associated with name %s\n", service_name);
     798           0 :         return;
     799             :     }
     800             : 
     801           0 :     if (!fo_svc_has_server(be_svc->fo_service, server)) {
     802           0 :         DEBUG(SSSDBG_OP_FAILURE,
     803             :               "The server %p is not valid anymore, cannot set its status\n",
     804             :                server);
     805           0 :         return;
     806             :     }
     807             : 
     808             :     /* Now we know that the server is valid */
     809           0 :     fo_set_port_status(server, status);
     810             : 
     811           0 :     if (status == PORT_WORKING) {
     812             :         /* We were successful in connecting to the server. Cycle through all
     813             :          * available servers next time */
     814           0 :         be_svc->first_resolved = NULL;
     815             :     }
     816             : }
     817             : 
     818             : /* Resolver back end interface */
     819             : static struct dp_option dp_res_default_opts[] = {
     820             :     { "lookup_family_order", DP_OPT_STRING, { "ipv4_first" }, NULL_STRING },
     821             :     { "dns_resolver_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
     822             :     { "dns_resolver_op_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
     823             :     { "dns_discovery_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     824             :     DP_OPTION_TERMINATOR
     825             : };
     826             : 
     827           7 : static errno_t be_res_get_opts(struct be_resolv_ctx *res_ctx,
     828             :                                struct confdb_ctx *cdb,
     829             :                                const char *conf_path)
     830             : {
     831             :     errno_t ret;
     832             :     const char *str_family;
     833             : 
     834           7 :     ret = dp_get_options(res_ctx, cdb, conf_path,
     835             :                          dp_res_default_opts,
     836             :                          DP_RES_OPTS,
     837             :                          &res_ctx->opts);
     838           7 :     if (ret != EOK) {
     839           0 :         return ret;
     840             :     }
     841             : 
     842           7 :     str_family = dp_opt_get_string(res_ctx->opts, DP_RES_OPT_FAMILY_ORDER);
     843           7 :     DEBUG(SSSDBG_CONF_SETTINGS, "Lookup order: %s\n", str_family);
     844             : 
     845           7 :     if (strcasecmp(str_family, "ipv4_first") == 0) {
     846           7 :         res_ctx->family_order = IPV4_FIRST;
     847           0 :     } else if (strcasecmp(str_family, "ipv4_only") == 0) {
     848           0 :         res_ctx->family_order = IPV4_ONLY;
     849           0 :     } else if (strcasecmp(str_family, "ipv6_first") == 0) {
     850           0 :         res_ctx->family_order = IPV6_FIRST;
     851           0 :     } else if (strcasecmp(str_family, "ipv6_only") == 0) {
     852           0 :         res_ctx->family_order = IPV6_ONLY;
     853             :     } else {
     854           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown value for option %s: %s\n",
     855             :               dp_res_default_opts[DP_RES_OPT_FAMILY_ORDER].opt_name, str_family);
     856           0 :         return EINVAL;
     857             :     }
     858             : 
     859           7 :     return EOK;
     860             : }
     861             : 
     862           7 : errno_t be_res_init(struct be_ctx *ctx)
     863             : {
     864             :     errno_t ret;
     865             : 
     866           7 :     if (ctx->be_res != NULL) {
     867           0 :         return EOK;
     868             :     }
     869             : 
     870           7 :     ctx->be_res = talloc_zero(ctx, struct be_resolv_ctx);
     871           7 :     if (!ctx->be_res) {
     872           0 :         return ENOMEM;
     873             :     }
     874             : 
     875           7 :     ret = be_res_get_opts(ctx->be_res, ctx->cdb, ctx->conf_path);
     876           7 :     if (ret != EOK) {
     877           0 :         talloc_zfree(ctx->be_res);
     878           0 :         return ret;
     879             :     }
     880             : 
     881          14 :     ret = resolv_init(ctx, ctx->ev,
     882           7 :                       dp_opt_get_int(ctx->be_res->opts,
     883             :                                      DP_RES_OPT_RESOLVER_OP_TIMEOUT),
     884           7 :                       &ctx->be_res->resolv);
     885           7 :     if (ret != EOK) {
     886           0 :         talloc_zfree(ctx->be_res);
     887           0 :         return ret;
     888             :     }
     889             : 
     890           7 :     return EOK;
     891             : }

Generated by: LCOV version 1.10