auth-worker-server.c revision 08d6658a4e2ec8104cd1307f6baa75fdb07a24f8
/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
#include "auth-common.h"
#include "ioloop.h"
#include "array.h"
#include "aqueue.h"
#include "network.h"
#include "istream.h"
#include "ostream.h"
#include "auth-request.h"
#include "auth-worker-client.h"
#include "auth-worker-server.h"
#include <stdlib.h>
#include <unistd.h>
#define AUTH_WORKER_LOOKUP_TIMEOUT_SECS 60
#define AUTH_WORKER_DELAY_WARN_SECS 3
#define AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS 300
struct auth_worker_request {
unsigned int id;
const char *data_str;
struct auth_request *auth_request;
};
struct auth_worker_connection {
int fd;
struct auth_worker_request *request;
unsigned int id_counter;
unsigned int shutdown:1;
};
static unsigned int idle_count;
static struct aqueue *worker_request_queue;
static time_t auth_worker_last_warn;
static char *worker_socket_path;
{
if (idle_count > 1)
else
}
{
}
struct auth_worker_request *request)
{
i_warning("auth workers: Auth request was queued for %d "
"seconds, %d left in queue",
}
idle_count--;
}
{
if (aqueue_count(worker_request_queue) == 0)
return;
}
{
struct auth_worker_connection *conn;
return NULL;
if (fd >= 0)
break;
/* we're busy. */
/* master didn't yet create it? */
} else {
i_fatal("net_connect_unix(%s) failed: %m",
}
if (try == 50) {
i_error("net_connect_unix(%s) "
"failed after %d secs: %m",
return NULL;
}
/* wait and try again */
usleep(100000);
}
FALSE);
idle_count++;
return conn;
}
{
struct auth_worker_connection **connp;
unsigned int i, count;
for (i = 0; i < count; i++) {
break;
}
}
idle_count--;
"Aborted: %s", reason);
"FAIL\t%d", PASSDB_RESULT_INTERNAL_FAILURE));
} T_END;
i_error("close(auth worker) failed: %m");
if (idle_count == 0 && restart) {
}
}
static struct auth_worker_connection *auth_worker_find_free(void)
{
struct auth_worker_connection **conns;
unsigned int i, count;
if (idle_count == 0)
return NULL;
for (i = 0; i < count; i++) {
return conns[i];
}
i_unreached();
return NULL;
}
struct auth_worker_request *request,
const char *line)
{
idle_count++;
}
{
unsigned int id;
case 0:
return;
case -1:
/* disconnected */
TRUE);
return;
case -2:
/* buffer full */
i_error("BUG: Auth worker sent us more than %d bytes",
(int)AUTH_WORKER_MAX_LINE_LENGTH);
return;
}
continue;
}
continue;
NULL, 10);
line + 1);
} else {
i_error("BUG: Worker sent reply with id %u, "
} else {
i_error("BUG: Worker sent reply with id %u, "
"none was expected", id);
}
return;
}
}
else
}
struct auth_stream_reply *data,
{
struct auth_worker_connection *conn;
struct auth_worker_request *request;
if (aqueue_count(worker_request_queue) > 0) {
/* requests are already being queued, no chance of
} else {
/* no free connections, create a new one */
}
}
else {
/* reached the limit, queue the request */
}
}
{
const char *env;
if (array_is_created(&connections)) {
/* already initialized */
return;
}
i_fatal("AUTH_WORKER_PATH environment not set");
(void)auth_worker_create(auth);
}
void auth_worker_server_deinit(void)
{
if (!array_is_created(&connections))
return;
while (array_count(&connections) > 0) {
}
}