auth-worker-server.c revision 226259ee6fb9830dafc1a5ba1e95bf5a4345b406
/* Copyright (c) 2005-2008 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "array.h"
#include "ioloop.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_MAX_OUTBUF_SIZE 10240
struct auth_worker_request {
unsigned int id;
struct auth_request *auth_request;
};
struct auth_worker_connection {
int fd;
unsigned int id_counter;
unsigned int request_count;
unsigned int requests_left;
};
static unsigned int idle_count;
static unsigned int auth_workers_max;
static unsigned int auth_workers_max_request_count;
static char *worker_socket_path;
static struct auth_worker_connection *auth_worker_create(void)
{
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 == 5) {
i_fatal("net_connect_unix(%s) "
"failed after %d tries: %m",
}
/* not created yet? try again */
sleep(1);
}
FALSE);
idle_count++;
return conn;
}
{
struct auth_worker_connection **connp;
struct auth_worker_request *requests;
unsigned int i, count;
const char *reply;
for (i = 0; i < count; i++) {
break;
}
}
if (conn->request_count == 0)
idle_count--;
/* abort all pending requests */
for (i = 0; i < count; i++) {
T_BEGIN {
reply);
} T_END;
}
}
i_error("close(auth worker) failed: %m");
}
static struct auth_worker_request *
unsigned int id)
{
struct auth_worker_request *requests;
unsigned int i, count;
for (i = 0; i < count; i++) {
return &requests[i];
}
return NULL;
}
static struct auth_worker_connection *auth_worker_find_free(void)
{
unsigned int i, count;
if (idle_count > 0) {
/* there exists at least one idle connection, use it */
for (i = 0; i < count; i++) {
if (conn[i]->request_count == 0)
return conn[i];
}
i_unreached();
}
/* first the connection with least data in output buffer */
for (i = 0; i < count; i++) {
}
}
return best;
}
struct auth_worker_request *request,
const char *line)
{
/* mark the record empty so it can be used for future requests */
/* update counters */
conn->request_count--;
if (conn->request_count == 0)
idle_count++;
}
{
struct auth_worker_request *request;
unsigned int id;
case 0:
return;
case -1:
/* disconnected */
return;
case -2:
/* buffer full */
i_error("BUG: Auth worker sent us more than %d bytes",
(int)AUTH_WORKER_MAX_LINE_LENGTH);
return;
}
continue;
T_BEGIN {
NULL, 10);
} T_END;
}
if (conn->requests_left == 0) {
if (idle_count == 0)
}
}
static struct auth_worker_request *
{
struct auth_worker_request *request;
}
struct auth_stream_reply *data,
{
struct auth_worker_connection *conn;
struct auth_worker_request *request;
/* no connections currently. can happen if all have been
idle for last 10 minutes. create a new one. */
conn = auth_worker_create();
"Couldn't create new auth worker");
return;
}
}
"All auth workers are busy");
return;
}
/* find an empty request */
if (idle_count == 0) {
/* this request was queued, we need new workers */
}
conn->requests_left--;
if (conn->request_count++ == 0)
idle_count--;
}
{
struct auth_worker_connection **conn;
unsigned int i, count;
if (idle_count <= 1)
return;
/* remove connections which we haven't used for a long time.
this works because auth_worker_find_free() always returns the
first free connection. */
for (i = 0; i < count; i++) {
/* remove just one. easier.. */
auth_worker_destroy(conn[i]);
break;
}
}
}
void auth_worker_server_init(void)
{
const char *env;
if (array_is_created(&connections)) {
/* already initialized */
return;
}
i_fatal("AUTH_WORKER_PATH environment not set");
i_fatal("AUTH_WORKER_MAX_COUNT environment not set");
i_fatal("AUTH_WORKER_MAX_REQUEST_COUNT environment not set");
if (auth_workers_max_request_count == 0)
auth_workers_max_request_count = (unsigned int)-1;
}
void auth_worker_server_deinit(void)
{
struct auth_worker_connection **connp;
if (!array_is_created(&connections))
return;
while (array_count(&connections) > 0) {
}
timeout_remove(&to);
}