Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0bfa5b0
failover: use setter to set active server in vtable_op
pbrezina Jul 21, 2026
30dbb03
failover: mark fo context as offline if there are no more servers to try
pbrezina Jul 21, 2026
45dc6aa
failover: check if there is any space for candidate servers
pbrezina Jul 21, 2026
4ee341a
failover: always check result of talloc_reference
pbrezina Jul 21, 2026
aecb7b2
failover: set active server and connection only in transaction
pbrezina Jul 21, 2026
70a12d6
failover: correctly obtain reference to active server
pbrezina Jul 21, 2026
9acf0f5
failover: return ERR_OFFLINE from transaction
pbrezina Jul 21, 2026
4dd9f94
failover: store force_tls parameter in state
pbrezina Jul 22, 2026
ffe0a62
failover: add sss_failover_get_active_server
pbrezina Jul 22, 2026
773d78a
failover: add sss_failover_server_is_working
pbrezina Jul 22, 2026
d2fd103
failover: reuse existing connection if possible
pbrezina Jul 22, 2026
29bbdb2
failover: add helpers to check active server functionality
pbrezina Jul 22, 2026
39bcb7a
failover: remove addr_changed and reuse_connection from connection code
pbrezina Jul 22, 2026
0c0bf29
failover: removed unused type definitions
pbrezina Jul 22, 2026
d897598
failover: refactor sss_failover_set_connection
pbrezina Jul 22, 2026
eb7f639
failover: notify backend when connection is being dropped
pbrezina Jul 22, 2026
9620088
failover: add sss_failover_active_server_cmp
pbrezina Jul 23, 2026
cada60f
failover: name all active_server access function consistently
pbrezina Jul 23, 2026
ddf01d1
failover: name all connection access function consistently
pbrezina Jul 23, 2026
6e30377
failover: add sss_failover_connection_cmp
pbrezina Jul 23, 2026
18a476a
failover: add helpers to drop connection and active server
pbrezina Jul 23, 2026
276a461
failover: add server to LDAP connection
pbrezina Jul 23, 2026
ada9fd7
failover: explicitly terminated LDAP connection in destructor
pbrezina Jul 23, 2026
5396d0b
failover: implement connection expiration
pbrezina Jul 23, 2026
22c023b
failover: check that vtable functions are set in vtable_op
pbrezina Jul 23, 2026
1c3ba02
failover: drop connection when changing active server
pbrezina Jul 23, 2026
f1c313e
failover: implement vtable methods to track operation start and end
pbrezina Jul 23, 2026
42c2ae8
failover: implement ldap connection idle handler
pbrezina Jul 23, 2026
04266f6
DO NOT PUSH TO MASTER minimal: setup idle handler
pbrezina Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 192 additions & 10 deletions src/providers/failover/failover.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ sss_failover_init(TALLOC_CTX *mem_ctx,

/* We are not connected to any server yet. */
fctx->active_server = NULL;
fctx->state = SSS_FAILOVER_STATE_DISCONNECTED;

fctx->vtable = talloc_zero(fctx, struct sss_failover_vtable);
if (fctx->vtable == NULL) {
Expand Down Expand Up @@ -165,7 +166,22 @@ sss_failover_init(TALLOC_CTX *mem_ctx,
}

void
sss_failover_set_active_server(struct sss_failover_ctx *fctx,
sss_failover_mark_offline(struct sss_failover_ctx *fctx)
{
sss_failover_active_server_set(fctx, NULL);

DEBUG(SSSDBG_OP_FAILURE, "Failover [%s] is going offline\n", fctx->name);
fctx->state = SSS_FAILOVER_STATE_OFFLINE;
}

bool
sss_failover_is_offline(struct sss_failover_ctx *fctx)
{
return fctx->state == SSS_FAILOVER_STATE_OFFLINE;
}

void
sss_failover_active_server_set(struct sss_failover_ctx *fctx,
struct sss_failover_server *server)
{
if (fctx->active_server != NULL) {
Expand All @@ -178,37 +194,203 @@ sss_failover_set_active_server(struct sss_failover_ctx *fctx,
fctx->active_server->name);

talloc_unlink(fctx, fctx->active_server);

/* Also remove the connection associated with this server. */
sss_failover_connection_set(fctx, NULL);
fctx->active_server = NULL;
}

if (server == NULL) {
DEBUG(SSSDBG_TRACE_FUNC,
"Setting active server to NULL (we are not connected)\n");
sss_failover_connection_set(fctx, NULL);
fctx->active_server = NULL;
return;
}

DEBUG(SSSDBG_TRACE_FUNC, "Setting new active server %s\n", server->name);
fctx->active_server = talloc_reference(fctx, server);
if (fctx->active_server == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
sss_failover_connection_set(fctx, NULL);
return;
}
}

void
sss_failover_set_connection(struct sss_failover_ctx *fctx, void *connection)
sss_failover_active_server_remove(struct sss_failover_ctx *fctx,
struct sss_failover_server *server)
{
if (fctx->connection != NULL) {
if (connection == fctx->connection) {
/* it is the same connection, nothing to do */
return;
}
/* We want to only remove the server if it is still the active one. */
if (!sss_failover_active_server_cmp(fctx, server)) {
return;
}

sss_failover_active_server_set(fctx, NULL);
}

struct sss_failover_server *
sss_failover_active_server_get_ref(TALLOC_CTX *mem_ctx,
struct sss_failover_ctx *fctx)
{
void *srv;

if (fctx->active_server == NULL) {
return NULL;
}

srv = talloc_reference(mem_ctx, fctx->active_server);
if (srv == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
return NULL;
}

return srv;
}

bool
sss_failover_active_server_cmp(struct sss_failover_ctx *fctx,
struct sss_failover_server *server)
{
return fctx->active_server == server;
}

bool
sss_failover_active_server_is_working(struct sss_failover_ctx *fctx)
{
if (fctx->active_server == NULL) {
return false;
}

return sss_failover_server_is_working(fctx->active_server);
}

bool
sss_failover_active_server_maybe_working(struct sss_failover_ctx *fctx)
{
if (fctx->active_server == NULL) {
return false;
}

return sss_failover_server_maybe_working(fctx->active_server);
}

void
sss_failover_connection_set(struct sss_failover_ctx *fctx, void *connection)
{
size_t ref_count;
void *ptr;

if (connection == fctx->connection) {
/* It is the same connection, nothing to do. This also covers the case
* where both are set to NULL. */
return;
}

ptr = fctx->connection;

if (fctx->connection != NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Releasing old connection %p\n",
fctx->connection);

talloc_unlink(fctx, fctx->connection);
ref_count = talloc_reference_count(fctx->connection);
if (ref_count == 0) {
DEBUG(SSSDBG_TRACE_FUNC, "The connection is no longer used, it "
"will be freed immediately\n");
} else {
DEBUG(SSSDBG_TRACE_FUNC,
"The connection is still used at %zu places, it will be "
"freed once it reaches 0\n",
ref_count - 1);
}

/* Old connection is removed. At this point we are not connected. */
fctx->connection = NULL;
fctx->state = SSS_FAILOVER_STATE_DISCONNECTED;

/* Notify backend that this connection is dropped. */
if (fctx->vtable->disconnected.cb != NULL) {
fctx->vtable->disconnected.cb(fctx, ptr,
fctx->vtable->disconnected.data);
}

/* If this is the last parent, the connection will be gracefully
* terminated via talloc destructor. Otherwise it will wait until the
* refcount drops to zero. */
talloc_unlink(fctx, ptr);
}

if (connection == NULL) {
DEBUG(SSSDBG_TRACE_FUNC, "Connection %p was dropped\n", ptr);
return;
}

if (fctx->active_server == NULL) {
/* This may be a bug in the code or OOM scenario that we can't detect in
* caller to simplify the API. Let's be defensive here. */
DEBUG(SSSDBG_OP_FAILURE, "Trying to set connection without an active "
"server, connection was dropped\n");
return;
}

DEBUG(SSSDBG_TRACE_FUNC, "Setting new connection %p\n", connection);
fctx->connection = talloc_steal(fctx, connection);
fctx->state = SSS_FAILOVER_STATE_CONNECTED;
}

void
sss_failover_connection_remove(struct sss_failover_ctx *fctx,
void *conn)
{
/* We want to only remove the connection if it is still the active one. */
if (!sss_failover_connection_cmp(fctx, conn)) {
return;
}

sss_failover_connection_set(fctx, NULL);
}

void *
sss_failover_get_connection(TALLOC_CTX *mem_ctx, struct sss_failover_ctx *fctx)
sss_failover_connection_get_ref(TALLOC_CTX *mem_ctx, struct sss_failover_ctx *fctx)
{
void *conn;

if (fctx->connection == NULL) {
return NULL;
}

return talloc_reference(mem_ctx, fctx->connection);
conn = talloc_reference(mem_ctx, fctx->connection);
if (conn == NULL) {
DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
return NULL;
}

return conn;
}

bool
sss_failover_connection_cmp(struct sss_failover_ctx *fctx,
void *conn)
{
return fctx->connection == conn;
}

void
sss_failover_connection_op_start(struct sss_failover_ctx *fctx,
void *connection)
{
if (fctx->vtable->conn_op_start.cb != NULL) {
fctx->vtable->conn_op_start.cb(fctx, connection,
fctx->vtable->conn_op_start.data);
}
}

void
sss_failover_connection_op_done(struct sss_failover_ctx *fctx,
void *connection)
{
if (fctx->vtable->conn_op_done.cb != NULL) {
fctx->vtable->conn_op_done.cb(fctx, connection,
fctx->vtable->conn_op_done.data);
}
}
Loading
Loading