fail_over.c revision 3765c2f9d4ba8aeffe140a8c5ab88acd79c66768
/*
SSSD
Fail over helper functions.
Authors:
Martin Nagy <mnagy@redhat.com>
Copyright (C) Red Hat, Inc 2009
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdbool.h>
#include <strings.h>
#include <talloc.h>
#include "util/dlinklist.h"
#include "util/refcount.h"
#include "providers/fail_over.h"
#include "resolv/async_resolv.h"
#define DEFAULT_PORT_STATUS PORT_NEUTRAL
struct fo_ctx {
struct fo_service *service_list;
struct server_common *server_common_list;
struct fo_options *opts;
};
struct fo_service {
struct fo_service *prev;
struct fo_service *next;
char *name;
struct fo_server *active_server;
struct fo_server *last_tried_server;
struct fo_server *server_list;
};
struct fo_server {
void *user_data;
int port;
int port_status;
struct fo_service *service;
struct timeval last_status_change;
struct server_common *common;
};
struct server_common {
struct server_common *prev;
struct server_common *next;
char *name;
struct resolve_service_request *request_list;
int server_status;
struct timeval last_status_change;
};
struct resolve_service_request {
struct resolve_service_request *prev;
struct resolve_service_request *next;
struct server_common *server_common;
struct tevent_req *req;
};
struct status {
int value;
struct timeval last_change;
};
struct fo_ctx *
{
return NULL;
}
return NULL;
}
return ctx;
}
static const char *
{
switch (status) {
case PORT_NEUTRAL:
return "neutral";
case PORT_WORKING:
return "working";
case PORT_NOT_WORKING:
return "not working";
}
return "unknown port status";
}
static const char *
{
switch (status) {
case SERVER_NAME_NOT_RESOLVED:
return "name not resolved";
case SERVER_RESOLVING_NAME:
return "resolving name";
case SERVER_NAME_RESOLVED:
return "name resolved";
case SERVER_WORKING:
return "working";
case SERVER_NOT_WORKING:
return "not working";
}
return "unknown server status";
}
/*
* This function will return the status of the server. If the status was
* last updated a long time ago, we will first reset the status.
*/
static enum server_status
{
return SERVER_NAME_RESOLVED;
SERVER_NAME(server)));
}
}
}
/*
* This function will return the status of the service. If the status was
* last updated a long time ago, we will first reset the status.
*/
static enum port_status
{
}
}
return server->port_status;
}
static int
{
return 0;
return 1;
}
static int
{
if (!server_works(server))
return 0;
return 0;
return 1;
}
static int
{
return 0;
}
int
struct fo_service **_service)
{
struct fo_service *service;
int ret;
if (_service) {
}
return EEXIST;
return ret;
}
return ENOMEM;
return ENOMEM;
}
if (_service) {
}
return EOK;
}
int
struct fo_service **_service)
{
struct fo_service *service;
return EOK;
}
}
return ENOENT;
}
static int
struct server_common **_common)
{
struct server_common *common;
return ENOMEM;
return EOK;
}
}
return ENOENT;
}
static int server_common_destructor(void *memptr)
{
struct server_common *common;
if (common->request_list) {
return -1;
}
return 0;
}
static struct server_common *
{
struct server_common *common;
return NULL;
return NULL;
}
return common;
}
int
void *user_data)
{
int ret;
continue;
return EEXIST;
return EEXIST;
}
}
return ENOMEM;
return ENOMEM;
}
return ret;
}
}
return EOK;
}
static int
{
/* If we already have a working server, use that one. */
if (service_works(server)) {
goto done;
}
}
/*
* Otherwise iterate through the server list.
*/
/* First, try servers after the last one we tried. */
if (service_works(server)) {
goto done;
}
}
}
/* If none were found, try at the start. */
if (service_works(server)) {
goto done;
}
break;
}
}
return ENOENT;
done:
return EOK;
}
static int
{
return 0;
}
static int
{
struct resolve_service_request *request;
return ENOMEM;
}
return ENOMEM;
}
return EOK;
}
/*******************************************************************
* Get server to connect to. *
*******************************************************************/
struct resolve_service_state {
};
struct tevent_req *
struct fo_service *service)
{
int ret;
struct tevent_req *req;
struct tevent_req *subreq;
struct resolve_service_state *state;
return NULL;
goto done;
}
/* This server doesn't have a name, we don't do name resolution. */
return req;
}
switch (get_server_status(server)) {
case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */
goto done;
}
/* FALLTHROUGH */
case SERVER_RESOLVING_NAME:
/* Name resolution is already under way. Just add ourselves into the
* waiting queue so we get notified after the operation is finished. */
goto done;
break;
default: /* The name is already resolved. Return immediately. */
break;
}
done:
}
return req;
}
enum server_status status);
static void
{
int resolv_status;
struct resolve_service_request *request;
struct server_common *common;
int ret;
}
} else {
}
/* Take care of all requests for this server. */
if (resolv_status) {
/* FIXME FIXME: resolv_status is an ARES error.
* but any caller will expect classic error codes.
* also the send() function may return ENOENT, so this mix
* IS explosive (ENOENT = 2 = ARES_EFORMER) */
} else {
}
}
}
int
{
struct resolve_service_state *state;
/* always return the server if asked for, otherwise the caller
* cannot mark it as faulty in case we return an error */
if (server)
return EOK;
}
static void
enum server_status status)
{
}
void
{
return;
}
}
void
{
if (status == PORT_WORKING) {
}
}
void *
{
}
int
{
}
{
}
struct hostent *
{
return NULL;
}
}