auth-worker-server.c revision 4426132a36ad4d5ba421f7bae9709f91fef37180
/* Copyright (C) 2005 Timo Sirainen */
#include "common.h"
#include "buffer.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 *request;
const char *reply;
for (i = 0; i < size; i++) {
sizeof(*connp));
break;
}
}
if (conn->request_count == 0)
idle_count--;
/* abort all pending requests */
for (i = 0; i < size; i++) {
}
}
i_error("close(auth worker) failed: %m");
}
static struct auth_worker_request *
unsigned int id)
{
struct auth_worker_request *request;
for (i = 0; i < size; i++) {
return &request[i];
}
return NULL;
}
static struct auth_worker_connection *auth_worker_find_free(void)
{
if (idle_count > 0) {
/* there exists at least one idle connection, use it */
for (i = 0; i < size; 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 < size; 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_push();
t_pop();
}
if (conn->requests_left == 0) {
if (idle_count == 0)
}
}
static struct auth_worker_request *
{
struct auth_worker_request *request;
for (i = 0; i < size; i++) {
return &request[i];
}
}
{
struct auth_worker_connection *conn;
struct auth_worker_request *request;
const char *reply;
/* 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;
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 < size; i++) {
/* remove just one. easier.. */
auth_worker_destroy(conn[i]);
break;
}
}
}
void auth_worker_server_init(void)
{
const char *env;
if (connections != NULL) {
/* 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;
sizeof(struct auth_worker_connection) * 16);
}
void auth_worker_server_deinit(void)
{
struct auth_worker_connection **connp;
if (connections == NULL)
return;
while (connections->used > 0) {
}
connections = NULL;
timeout_remove(&to);
}