summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2023-11-27 16:57:05 +0100
committerSimon Rettberg2023-11-27 16:57:05 +0100
commitba2e716a8357496c3a834a8e799583ef58f95f82 (patch)
tree8e62953ff2c5e2944a4577720e5c588c77978d77
parentFix and improve numeric uid handling (diff)
downloadldadp-ba2e716a8357496c3a834a8e799583ef58f95f82.tar.gz
ldadp-ba2e716a8357496c3a834a8e799583ef58f95f82.tar.xz
ldadp-ba2e716a8357496c3a834a8e799583ef58f95f82.zip
Add autorestart option to exit(1) on unresponsive upstream
-rw-r--r--helper.c1
-rw-r--r--helper.h3
-rw-r--r--ldadp.c2
-rw-r--r--proxy.c51
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 <stdarg.h>
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];
}
/*