From ba2e716a8357496c3a834a8e799583ef58f95f82 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Mon, 27 Nov 2023 16:57:05 +0100 Subject: Add autorestart option to exit(1) on unresponsive upstream --- helper.c | 1 + helper.h | 3 +++ ldadp.c | 2 ++ proxy.c | 51 ++++++++++++++++++++++++++++++++++++++++----------- 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/helper.c b/helper.c index 6c51bab..93ed207 100644 --- a/helper.c +++ b/helper.c @@ -12,6 +12,7 @@ #include DebugLevel _debugLevel = DEBUG_WARNING; +int _autoRestart = 0; void bail(char *args, ...) { diff --git a/helper.h b/helper.h index 7aaece7..3b20545 100644 --- a/helper.h +++ b/helper.h @@ -33,7 +33,10 @@ typedef enum { DEBUG_TRACE = 4, } DebugLevel; +/** Debug level for logging */ extern DebugLevel _debugLevel; +/** Automatically restart on connection errors? */ +extern int _autoRestart; void plog(const DebugLevel messageLevel, char *args, ...); diff --git a/ldadp.c b/ldadp.c index 3f69745..2152903 100644 --- a/ldadp.c +++ b/ldadp.c @@ -155,6 +155,8 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key, keyFile = strdup(value); } else if (strcmp(key, "debug") == 0) { _debugLevel = atoi(value); + } else if (strcmp(key, "autorestart") == 0) { + _autoRestart = atoi(value) != 0; } else { printf("Unknown local config option '%s'\n", key); } diff --git a/proxy.c b/proxy.c index f3588ef..0df3729 100644 --- a/proxy.c +++ b/proxy.c @@ -48,10 +48,12 @@ typedef struct unsigned long serverMessageId; epoll_client_t *client; attr_t attr; + time_t started; } pending_t; static pending_t _pendingRequest[MAXPENDING]; static int _pendingCount = 0; +static int _problemCount = 0; // Attributes static struct string s_uid, s_sAMAccountName, s_objectSid, s_homeMount, s_memberUid, s_realAccount; @@ -242,15 +244,27 @@ BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen) return TRUE; } +/** + * Client notifies us about how it's disconnecting + */ void proxy_removeClient(epoll_client_t * const client) { int i, lastValid = -1; + BOOL problem = FALSE; for (i = 0; i < _pendingCount; ++i) { if (_pendingRequest[i].client == client) { plog(DEBUG_TRACE, "RemoveClient success %p", client); _pendingRequest[i].client = NULL; + if (_autoRestart && _pendingRequest[i].started + 10 < time(NULL)) { + plog(DEBUG_WARNING, "Client has pending request, age %d", (int)(time(NULL) - _pendingRequest[i].started)); + problem = TRUE; + } + } else if (_pendingRequest[i].client != NULL) { + lastValid = i; } - else if (_pendingRequest[i].client != NULL) lastValid = i; + } + if (problem && ++_problemCount > 5) { + bail("Too many unanswered requests, bailing out"); } _pendingCount = lastValid + 1; if (client->fixedServer != NULL) { @@ -260,6 +274,9 @@ void proxy_removeClient(epoll_client_t * const client) } } +/** + * Server is closing the connection, get rid of according + */ void proxy_removeServer(epoll_server_t * const server) { if (server->fixedClient != NULL) { @@ -304,6 +321,9 @@ BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen) return proxy_serverBindResponse(server, messageId, res, maxLen); case SearchResultEntry: case SearchResultDone: + if (_autoRestart && _problemCount > 0) { + --_problemCount; + } return proxy_serverSearchResult(server, messageId, op, res, maxLen); case SearchResultReference: // Just ignore these for now @@ -327,19 +347,28 @@ BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen) static pending_t* proxy_getFreePendingSlot(epoll_client_t *client) { - for (int i = 0; i < _pendingCount; ++i) { - if (_pendingRequest[i].client == NULL) { - memset(&_pendingRequest[i], 0, sizeof(pending_t)); - _pendingRequest[i].client = client; - return &_pendingRequest[i]; + time_t oldest = 0; + int i; + for (i = 0; i < _pendingCount; ++i) { + if (_pendingRequest[i].client == NULL) + break; + if (oldest == 0 || oldest > _pendingRequest[i].started) { + oldest = _pendingRequest[i].started; } } - if (_pendingCount < MAXPENDING) { - memset(&_pendingRequest[_pendingCount], 0, sizeof(pending_t)); - _pendingRequest[_pendingCount].client = client; - return &_pendingRequest[_pendingCount++]; + if (i == _pendingCount) { + if (_pendingCount >= MAXPENDING) { + if (_autoRestart && oldest + 30 < time(NULL)) { + bail("Bailing out: Request queue full and auto-restart enabled!"); + } + return NULL; + } + i = _pendingCount++; } - return NULL; + memset(&_pendingRequest[i], 0, sizeof(pending_t)); + _pendingRequest[i].client = client; + _pendingRequest[i].started = time(NULL); + return &_pendingRequest[i]; } /* -- cgit v1.2.3-55-g7522