auth-worker-server.c revision be5c76fabc7439fd33bc799bc3ab3f570799977b
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen#define AUTH_WORKER_DELAY_WARN_MIN_INTERVAL_SECS 300
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id;
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 *);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic const char *worker_socket_path;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void worker_input(struct auth_worker_connection *conn);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void auth_worker_destroy(struct auth_worker_connection **conn,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void auth_worker_idle_timeout(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_call_timeout(struct auth_worker_connection *conn)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_worker_destroy(&conn, "Lookup timed out", TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_request_send(struct auth_worker_connection *conn,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ioloop_time - request->created > AUTH_WORKER_DELAY_WARN_SECS &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_warning("auth workers: Auth request was queued for %d "
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "seconds, %d left in queue",
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen iov[0].iov_base = t_strdup_printf("%d\t", request->id);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen conn->to = timeout_add(AUTH_WORKER_LOOKUP_TIMEOUT_SECS * 1000,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void auth_worker_request_send_next(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct auth_worker_request *request, *const *requestp;
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainenstatic void auth_worker_send_handshake(struct auth_worker_connection *conn)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_printfa(str, "VERSION\tauth-worker\t%u\t%u\n",
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen binary_to_hex_append(str, passdb_md5, sizeof(passdb_md5));
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen binary_to_hex_append(str, userdb_md5, sizeof(userdb_md5));
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen o_stream_send(conn->output, str_data(str), str_len(str));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic struct auth_worker_connection *auth_worker_create(void)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (array_count(&connections) >= global_auth_settings->worker_max_count)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen fd = net_connect_unix_with_retries(worker_socket_path, 5000);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen conn = i_new(struct auth_worker_connection, 1);
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen conn->input = i_stream_create_fd(fd, AUTH_WORKER_MAX_LINE_LENGTH,
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,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenstatic void auth_worker_destroy(struct auth_worker_connection **_conn,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen unsigned int idx;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_error("auth worker: Aborted request: %s", reason);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic struct auth_worker_connection *auth_worker_find_free(void)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen array_foreach_modifiable(&connections, conns) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenstatic void auth_worker_request_handle(struct auth_worker_connection *conn,
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen /* multi-line reply, not finished yet */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen conn->to = timeout_add(AUTH_WORKER_MAX_IDLE_SECS * 1000,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (!request->callback(line, request->context) && conn->io != NULL)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainenstatic void worker_input(struct auth_worker_connection *conn)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int id;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* disconnected */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen auth_worker_destroy(&conn, "Worker process died unexpectedly",
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* buffer full */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("BUG: Auth worker sent us more than %d bytes",
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen auth_worker_destroy(&conn, "Worker is buggy", TRUE);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen while ((line = i_stream_next_line(conn->input)) != NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen id = (unsigned int)strtoul(t_strcut(id_str, '\t'),
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (conn->request != NULL && id == conn->request->id) {
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen auth_worker_request_handle(conn, conn->request,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen auth_worker_destroy(&conn, "Worker is buggy", TRUE);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* there's still a pending request */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_worker_destroy(&conn, "Max requests limit", TRUE);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenauth_worker_call(pool_t pool, struct auth_stream_reply *data,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_worker_callback_t *callback, void *context)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen request = p_new(pool, struct auth_worker_request, 1);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen request->data_str = p_strdup(pool, auth_stream_reply_export(data));
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* requests are already being queued, no chance of
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* no free connections, create a new one */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* reached the limit, queue the request */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen aqueue_append(worker_request_queue, &request);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenvoid auth_worker_server_resume_input(struct auth_worker_connection *conn)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen conn->io = io_add(conn->fd, IO_READ, worker_input, conn);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen worker_request_queue = aqueue_init(&worker_request_array.arr);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen connp = array_idx_modifiable(&connections, 0);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen auth_worker_destroy(&conn, "Shutting down", FALSE);