auth-worker-server.c revision be5c76fabc7439fd33bc799bc3ab3f570799977b
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "ioloop.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "array.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "aqueue.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "network.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "ostream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "auth-request.h"
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#include "auth-worker-client.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "auth-worker-server.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <stdlib.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <unistd.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define AUTH_WORKER_LOOKUP_TIMEOUT_SECS 60
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define AUTH_WORKER_MAX_IDLE_SECS (60*5)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define AUTH_WORKER_DELAY_WARN_SECS 3
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen#define AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS 300
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainenstruct auth_worker_request {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen time_t created;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *data_str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_callback_t *callback;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen void *context;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen};
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct auth_worker_connection {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen int fd;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen struct io *io;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen struct istream *input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct ostream *output;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct timeout *to;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen struct auth_worker_request *request;
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen unsigned int id_counter;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen unsigned int shutdown:1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen};
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainenstatic ARRAY_DEFINE(connections, struct auth_worker_connection *) = ARRAY_INIT;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic unsigned int idle_count;
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainenstatic ARRAY_DEFINE(worker_request_array, struct auth_worker_request *);
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic struct aqueue *worker_request_queue;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic time_t auth_worker_last_warn;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic const char *worker_socket_path;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void worker_input(struct auth_worker_connection *conn);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void auth_worker_destroy(struct auth_worker_connection **conn,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen const char *reason, bool restart);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void auth_worker_idle_timeout(struct auth_worker_connection *conn)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen i_assert(conn->request == NULL);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (idle_count > 1)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen auth_worker_destroy(&conn, NULL, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen timeout_reset(conn->to);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_call_timeout(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_assert(conn->request != NULL);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_worker_destroy(&conn, "Lookup timed out", TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_request_send(struct auth_worker_connection *conn,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_request *request)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen struct const_iovec iov[3];
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ioloop_time - request->created > AUTH_WORKER_DELAY_WARN_SECS &&
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen ioloop_time - auth_worker_last_warn >
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen auth_worker_last_warn = ioloop_time;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_warning("auth workers: Auth request was queued for %d "
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "seconds, %d left in queue",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (int)(ioloop_time - request->created),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen aqueue_count(worker_request_queue));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen request->id = ++conn->id_counter;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen iov[0].iov_base = t_strdup_printf("%d\t", request->id);
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen iov[0].iov_len = strlen(iov[0].iov_base);
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen iov[1].iov_base = request->data_str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen iov[1].iov_len = strlen(request->data_str);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen iov[2].iov_base = "\n";
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen iov[2].iov_len = 1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen o_stream_sendv(conn->output, iov, 3);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen i_assert(conn->request == NULL);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen conn->request = request;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen timeout_remove(&conn->to);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen conn->to = timeout_add(AUTH_WORKER_LOOKUP_TIMEOUT_SECS * 1000,
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen auth_worker_call_timeout, conn);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen idle_count--;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_request_send_next(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_request *request, *const *requestp;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (aqueue_count(worker_request_queue) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen requestp = array_idx(&worker_request_array,
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen aqueue_idx(worker_request_queue, 0));
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen request = *requestp;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen aqueue_delete_tail(worker_request_queue);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_request_send(conn, request);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainenstatic void auth_worker_send_handshake(struct auth_worker_connection *conn)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen{
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen string_t *str;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen unsigned char passdb_md5[MD5_RESULTLEN];
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen unsigned char userdb_md5[MD5_RESULTLEN];
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str = t_str_new(128);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_printfa(str, "VERSION\tauth-worker\t%u\t%u\n",
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen AUTH_WORKER_PROTOCOL_MAJOR_VERSION,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen AUTH_WORKER_PROTOCOL_MINOR_VERSION);
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen passdbs_generate_md5(passdb_md5);
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen userdbs_generate_md5(userdb_md5);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_append(str, "DBHASH\t");
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen str_append_c(str, '\t');
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen str_append_c(str, '\n');
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic struct auth_worker_connection *auth_worker_create(void)
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen{
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen struct auth_worker_connection *conn;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen int fd;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (array_count(&connections) >= global_auth_settings->worker_max_count)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fd = net_connect_unix_with_retries(worker_socket_path, 5000);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (fd == -1) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen i_fatal("net_connect_unix(%s) failed: %m",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen worker_socket_path);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen conn = i_new(struct auth_worker_connection, 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen conn->fd = fd;
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen FALSE);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen conn->io = io_add(fd, IO_READ, worker_input, conn);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen auth_worker_idle_timeout, conn);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen auth_worker_send_handshake(conn);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen idle_count++;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen array_append(&connections, &conn, 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return conn;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenstatic void auth_worker_destroy(struct auth_worker_connection **_conn,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen const char *reason, bool restart)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen struct auth_worker_connection *conn = *_conn;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen struct auth_worker_connection *const *conns;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen unsigned int idx;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen *_conn = NULL;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen array_foreach(&connections, conns) {
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (*conns == conn) {
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen idx = array_foreach_idx(&connections, conns);
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen array_delete(&connections, idx, 1);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen break;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen }
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen if (conn->request == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen idle_count--;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (conn->request != NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("auth worker: Aborted request: %s", reason);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen conn->request->callback(t_strdup_printf(
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen "FAIL\t%d", PASSDB_RESULT_INTERNAL_FAILURE),
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen conn->request->context);
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen io_remove(&conn->io);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_destroy(&conn->input);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen o_stream_destroy(&conn->output);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen timeout_remove(&conn->to);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (close(conn->fd) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("close(auth worker) failed: %m");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_free(conn);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (idle_count == 0 && restart) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen conn = auth_worker_create();
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen auth_worker_request_send_next(conn);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen }
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic struct auth_worker_connection *auth_worker_find_free(void)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct auth_worker_connection **conns;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (idle_count == 0)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return NULL;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen array_foreach_modifiable(&connections, conns) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct auth_worker_connection *conn = *conns;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (conn->request == NULL)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return conn;
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen }
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen i_unreached();
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return NULL;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenstatic void auth_worker_request_handle(struct auth_worker_connection *conn,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct auth_worker_request *request,
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen const char *line)
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen{
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen if (strncmp(line, "*\t", 2) == 0) {
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen /* multi-line reply, not finished yet */
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen } else {
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen conn->request = NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen timeout_remove(&conn->to);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_idle_timeout, conn);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen idle_count++;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (!request->callback(line, request->context) && conn->io != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_remove(&conn->io);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainenstatic void worker_input(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen const char *line, *id_str;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen switch (i_stream_read(conn->input)) {
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen case 0:
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen case -1:
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* disconnected */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen auth_worker_destroy(&conn, "Worker process died unexpectedly",
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen TRUE);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen case -2:
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* buffer full */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("BUG: Auth worker sent us more than %d bytes",
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen (int)AUTH_WORKER_MAX_LINE_LENGTH);
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen auth_worker_destroy(&conn, "Worker is buggy", TRUE);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (strcmp(line, "SHUTDOWN") == 0) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen conn->shutdown = TRUE;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen continue;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen id_str = line;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen line = strchr(line, '\t');
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen if (line == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen continue;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen id = (unsigned int)strtoul(t_strcut(id_str, '\t'),
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen NULL, 10);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (conn->request != NULL && id == conn->request->id) {
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen auth_worker_request_handle(conn, conn->request,
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen line + 1);
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen } else {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (conn->request != NULL) {
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen i_error("BUG: Worker sent reply with id %u, "
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen "expected %u", id, conn->request->id);
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen } else {
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen i_error("BUG: Worker sent reply with id %u, "
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen "none was expected", id);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_destroy(&conn, "Worker is buggy", TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (conn->request != NULL) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* there's still a pending request */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen } else if (conn->shutdown)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_worker_destroy(&conn, "Max requests limit", TRUE);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen else
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen auth_worker_request_send_next(conn);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstruct auth_worker_connection *
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenauth_worker_call(pool_t pool, struct auth_stream_reply *data,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_worker_callback_t *callback, void *context)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct auth_worker_connection *conn;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen struct auth_worker_request *request;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen request = p_new(pool, struct auth_worker_request, 1);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen request->created = ioloop_time;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen request->data_str = p_strdup(pool, auth_stream_reply_export(data));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen request->callback = callback;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen request->context = context;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (aqueue_count(worker_request_queue) > 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* requests are already being queued, no chance of
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen finding/creating a worker */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen conn = NULL;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen } else {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen conn = auth_worker_find_free();
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (conn == NULL) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* no free connections, create a new one */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen conn = auth_worker_create();
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (conn != NULL)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_worker_request_send(conn, request);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen else {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* reached the limit, queue the request */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen aqueue_append(worker_request_queue, &request);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return conn;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenvoid auth_worker_server_resume_input(struct auth_worker_connection *conn)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (conn->io == NULL)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen conn->io = io_add(conn->fd, IO_READ, worker_input, conn);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenvoid auth_worker_server_init(void)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen worker_socket_path = "auth-worker";
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen i_array_init(&worker_request_array, 128);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen worker_request_queue = aqueue_init(&worker_request_array.arr);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen i_array_init(&connections, 16);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenvoid auth_worker_server_deinit(void)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen struct auth_worker_connection **connp, *conn;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen while (array_count(&connections) > 0) {
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen connp = array_idx_modifiable(&connections, 0);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen conn = *connp;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen auth_worker_destroy(&conn, "Shutting down", FALSE);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen }
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen array_free(&connections);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen aqueue_deinit(&worker_request_queue);
88e9835c4d8973c62cd4db1ec7324ff46dd3ff15Timo Sirainen array_free(&worker_request_array);
88e9835c4d8973c62cd4db1ec7324ff46dd3ff15Timo Sirainen}
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen