dict-client.c revision 28a311381d783cc06e56f9baf1cb9f25634cbfe4
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "lib.h"
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen#include "llist.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "str.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "network.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "istream.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "ostream.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "dict-private.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include "dict-client.h"
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen#include <stdlib.h>
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include <unistd.h>
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen#include <fcntl.h>
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen/* Disconnect from dict server after this many milliseconds of idling after
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen sending a command. This timeout is short, because dict server does blocking
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen dict accesses, so it can handle only one client at a time. increasing the
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen timeout increases number of idling dict processes. */
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen#define DICT_CLIENT_TIMEOUT_MSECS 1000
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen pool_t pool;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen int fd;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *uri;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *username;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *path;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_data_type value_type;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen time_t last_connect_try;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct istream *input;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct ostream *output;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct io *io;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen struct timeout *to_idle;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *transactions;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int connect_counter;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int transaction_id_counter;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen unsigned int async_commits;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int in_iteration:1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int handshaked:1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict_iterate_context {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict_iterate_context ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen pool_t pool;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool failed;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstruct client_dict_transaction_context {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct dict_transaction_context ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *prev, *next;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen /* for async commits */
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_transaction_commit_callback_t *callback;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen void *context;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int id;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int connect_counter;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen unsigned int failed:1;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen unsigned int sent_begin:1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_connect(struct client_dict *dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenconst char *dict_client_escape(const char *src)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *p;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen string_t *dest;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* first do a quick lookup to see if there's anything to escape.
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen probably not. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen for (p = src; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\t' || *p == '\n' || *p == '\001')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\0')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return src;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dest = t_str_new(256);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_n(dest, src, p - src);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
7bf6a25a58184d3ff4714d76a402d61a0cca2c52Timo Sirainen for (; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen switch (*p) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case '\t':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\001');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, 't');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case '\n':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\001');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, 'n');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case '\001':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\001');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '1');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen default:
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, *p);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return str_c(dest);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenconst char *dict_client_unescape(const char *src)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *p;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen string_t *dest;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* first do a quick lookup to see if there's anything to unescape.
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen probably not. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen for (p = src; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\001')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\0')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return src;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dest = t_str_new(256);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_n(dest, src, p - src);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen for (; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p != '\001')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, *p);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen else if (p[1] != '\0') {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen p++;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen switch (*p) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case '1':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\001');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case 't':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\t');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen case 'n':
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen str_append_c(dest, '\n');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen break;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return str_c(dest);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_send_query(struct client_dict *dict, const char *query)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen if (dict->output == NULL) {
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen /* not connected currently */
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen if (client_dict_connect(dict) < 0)
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen return -1;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen }
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen o_stream_flush(dict->output) < 0) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Send failed */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (!dict->handshaked) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* we're trying to send hello, don't try to reconnect */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Reconnect and try again. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_disconnect(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (client_dict_connect(dict) < 0)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen o_stream_flush(dict->output) < 0) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("write(%s) failed: %m", dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainenstatic int
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainenclient_dict_transaction_send_begin(struct client_dict_transaction_context *ctx)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen{
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (ctx->failed)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen return -1;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%u\n", DICT_PROTOCOL_CMD_BEGIN,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->id);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (client_dict_send_query(dict, query) < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->failed = TRUE;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen else
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->connect_counter = dict->connect_counter;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen return ctx->failed ? -1 : 0;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen}
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainenstatic int
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainenclient_dict_send_transaction_query(struct client_dict_transaction_context *ctx,
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen const char *query)
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen{
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (!ctx->sent_begin) {
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (client_dict_transaction_send_begin(ctx) < 0)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen return -1;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen ctx->sent_begin = TRUE;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen }
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen if (ctx->connect_counter != dict->connect_counter || ctx->failed)
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen return -1;
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen if (dict->output == NULL) {
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen /* not connected, this'll fail */
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen return -1;
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen }
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen o_stream_flush(dict->output) < 0) {
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen /* Send failed. Our transactions have died, so don't even try
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen to re-send the command */
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen ctx->failed = TRUE;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen client_dict_disconnect(dict);
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen return -1;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen }
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen return 0;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen}
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic struct client_dict_transaction_context *
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_find(struct client_dict *dict, unsigned int id)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen for (ctx = dict->transactions; ctx != NULL; ctx = ctx->next) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ctx->id == id)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return NULL;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic void
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_finish_transaction(struct client_dict *dict,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen unsigned int id, int ret)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ctx = client_dict_transaction_find(dict, id);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ctx == NULL) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("dict-client: Unknown transaction id %u", id);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ctx->callback != NULL)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ctx->callback(ret, ctx->context);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_REMOVE(&dict->transactions, ctx);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_free(ctx);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_assert(dict->async_commits > 0);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (--dict->async_commits == 0)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen io_remove(&dict->io);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic int client_dict_read_one_line(struct client_dict *dict, char **line_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen unsigned int id;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen char *line;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen int ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen *line_r = NULL;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen while ((line = i_stream_next_line(dict->input)) == NULL) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = i_stream_read(dict->input);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen switch (ret) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen case -1:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (dict->input->stream_errno != 0)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("read(%s) failed: %m", dict->path);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("read(%s) failed: Remote disconnected",
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict->path);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen case -2:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("read(%s) returned too much data", dict->path);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen default:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_assert(ret > 0);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (*line == DICT_PROTOCOL_REPLY_ASYNC_COMMIT) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen switch (line[1]) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen case DICT_PROTOCOL_REPLY_OK:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = 1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen case DICT_PROTOCOL_REPLY_NOTFOUND:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = 0;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen case DICT_PROTOCOL_REPLY_FAIL:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen default:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("dict-client: Invalid async commit line: %s",
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen line);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return 0;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_uint(line+2, &id) < 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("dict-client: Invalid ID");
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return 0;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen client_dict_finish_transaction(dict, id, ret);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen *line_r = line;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return 1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic bool client_dict_is_finished(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen return dict->transactions == NULL && !dict->in_iteration &&
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen dict->async_commits == 0;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_timeout(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen if (client_dict_is_finished(dict))
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_disconnect(dict);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainenstatic void client_dict_add_timeout(struct client_dict *dict)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen{
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen if (dict->to_idle != NULL)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen timeout_reset(dict->to_idle);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen else if (client_dict_is_finished(dict)) {
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen dict->to_idle = timeout_add(DICT_CLIENT_TIMEOUT_MSECS,
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_timeout, dict);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen }
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen}
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic char *client_dict_read_line(struct client_dict *dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen char *line;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen while (client_dict_read_one_line(dict, &line) == 0)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return line;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_connect(struct client_dict *dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *query;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_assert(dict->fd == -1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen if (dict->last_connect_try == ioloop_time) {
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen /* Try again later */
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen return -1;
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen }
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen dict->last_connect_try = ioloop_time;
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->fd = net_connect_unix(dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (dict->fd == -1) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("net_connect_unix(%s) failed: %m", dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Dictionary lookups are blocking */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen net_set_nonblock(dict->fd, FALSE);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen dict->input = i_stream_create_fd(dict->fd, (size_t)-1, FALSE);
74054d9e81a8447cee6049268f3cfd8d8a5d4d59Timo Sirainen dict->input->blocking = TRUE;
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen dict->output = o_stream_create_fd(dict->fd, 4096, FALSE);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->transaction_id_counter = 0;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict->async_commits = 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen query = t_strdup_printf("%c%u\t%u\t%d\t%s\t%s\n",
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen DICT_PROTOCOL_CMD_HELLO,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen DICT_CLIENT_PROTOCOL_MAJOR_VERSION,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen DICT_CLIENT_PROTOCOL_MINOR_VERSION,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen dict->value_type, dict->username, dict->uri);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (client_dict_send_query(dict, query) < 0) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_disconnect(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->handshaked = TRUE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->connect_counter++;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->handshaked = FALSE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen if (dict->to_idle != NULL)
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen timeout_remove(&dict->to_idle);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (dict->io != NULL)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen io_remove(&dict->io);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (dict->input != NULL)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_destroy(&dict->input);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (dict->output != NULL)
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen o_stream_destroy(&dict->output);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (dict->fd != -1) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (close(dict->fd) < 0)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("close(%s) failed: %m", dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->fd = -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenstatic struct dict *
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenclient_dict_init(struct dict *driver, const char *uri,
4073f0dbf3277f981a8fcee3b89ea15aaf380a7fTimo Sirainen enum dict_data_type value_type, const char *username,
4073f0dbf3277f981a8fcee3b89ea15aaf380a7fTimo Sirainen const char *base_dir)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict;
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen const char *dest_uri;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen pool_t pool;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen /* uri = [<path>] ":" <uri> */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dest_uri = strchr(uri, ':');
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (dest_uri == NULL) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("dict-client: Invalid URI: %s", uri);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return NULL;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen pool = pool_alloconly_create("client dict", 1024);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict = p_new(pool, struct client_dict, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->pool = pool;
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainen dict->dict = *driver;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen dict->value_type = value_type;
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen dict->username = p_strdup(pool, username);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->fd = -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen if (*uri != ':') {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* path given */
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen dict->path = p_strdup_until(pool, uri, dest_uri);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen } else {
4073f0dbf3277f981a8fcee3b89ea15aaf380a7fTimo Sirainen dict->path = p_strconcat(pool, base_dir,
4073f0dbf3277f981a8fcee3b89ea15aaf380a7fTimo Sirainen "/"DEFAULT_DICT_SERVER_SOCKET_FNAME, NULL);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->uri = p_strdup(pool, dest_uri + 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return &dict->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_deinit(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_disconnect(dict);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&dict->pool);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic int client_dict_wait(struct dict *_dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen char *line;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen int ret = 0;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen while (dict->async_commits > 0) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (client_dict_read_one_line(dict, &line) < 0) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen break;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen return ret;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_lookup(struct dict *_dict, pool_t pool,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *key, const char **value_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *line;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen int ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%s\n", DICT_PROTOCOL_CMD_LOOKUP,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen dict_client_escape(key));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ret = client_dict_send_query(dict, query);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret < 0)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* read reply */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen line = client_dict_read_line(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (line == NULL)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*line == DICT_PROTOCOL_REPLY_OK) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = p_strdup(pool, dict_client_unescape(line + 1));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return 1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen } else {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = NULL;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return *line == DICT_PROTOCOL_REPLY_NOTFOUND ? 0 : -1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic struct dict_iterate_context *
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainenclient_dict_iterate_init(struct dict *_dict, const char *const *paths,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen enum dict_iterate_flags flags)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (dict->in_iteration)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_panic("dict-client: Only one iteration supported");
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen dict->in_iteration = TRUE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_iterate_context, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->ctx.dict = _dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->pool = pool_alloconly_create("client dict iteration", 512);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen string_t *query = t_str_new(256);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen unsigned int i;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen str_printfa(query, "%c%d", DICT_PROTOCOL_CMD_ITERATE, flags);
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen for (i = 0; paths[i] != NULL; i++) {
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen str_append_c(query, '\t');
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen str_append(query, dict_client_escape(paths[i]));
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen }
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen str_append_c(query, '\n');
9c7f6dbf65ca01026e5f9c8c8b67c7e629c0b5e7Timo Sirainen if (client_dict_send_query(dict, str_c(query)) < 0)
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->failed = TRUE;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return &ctx->ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic bool client_dict_iterate(struct dict_iterate_context *_ctx,
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen const char **key_r, const char **value_r)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_iterate_context *)_ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen char *line, *value;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (ctx->failed)
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* read next reply */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen line = client_dict_read_line(dict);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen if (line == NULL) {
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen ctx->failed = TRUE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*line == '\0') {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* end of iteration */
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* line contains key \t value */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen p_clear(ctx->pool);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen switch (*line) {
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen case DICT_PROTOCOL_REPLY_OK:
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen value = strchr(++line, '\t');
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen break;
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen case DICT_PROTOCOL_REPLY_FAIL:
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen ctx->failed = TRUE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen default:
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen value = NULL;
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen break;
e4383dc44cc122924e65a533b105fd64bf566ebfTimo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (value == NULL) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* broken protocol */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("dict client (%s) sent broken reply", dict->path);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen ctx->failed = TRUE;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return FALSE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value++ = '\0';
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *key_r = p_strdup(ctx->pool, dict_client_unescape(line));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = p_strdup(ctx->pool, dict_client_unescape(value));
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return TRUE;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainenstatic int client_dict_iterate_deinit(struct dict_iterate_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_iterate_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_iterate_context *)_ctx;
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen int ret = ctx->failed ? -1 : 0;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen pool_unref(&ctx->pool);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_free(ctx);
3ab74daf30ed911af6ffdbc7e430f0534050a929Timo Sirainen dict->in_iteration = FALSE;
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
8d25b6ad05b99e75613cb045a121efd51e6afbb6Timo Sirainen return ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic struct dict_transaction_context *
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_init(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_transaction_context, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->ctx.dict = _dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->id = ++dict->transaction_id_counter;
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_PREPEND(&dict->transactions, ctx);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return &ctx->ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic void dict_async_input(struct client_dict *dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen{
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen char *line;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen size_t size;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen int ret;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_assert(!dict->in_iteration);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen do {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = client_dict_read_one_line(dict, &line);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen (void)i_stream_get_data(dict->input, &size);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen } while (ret == 0 && size > 0);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ret < 0)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen io_remove(&dict->io);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen}
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic int
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_commit(struct dict_transaction_context *_ctx,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen bool async,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_transaction_commit_callback_t *callback,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen void *context)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen int ret = ctx->failed ? -1 : 1;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ctx->sent_begin && !ctx->failed) T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query, *line;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen query = t_strdup_printf("%c%u\n", !async ?
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DICT_PROTOCOL_CMD_COMMIT :
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DICT_PROTOCOL_CMD_COMMIT_ASYNC,
03b10bd68ecd2307c7f505ddbdeee2d40a5d1441Timo Sirainen ctx->id);
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (client_dict_send_transaction_query(ctx, query) < 0)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ret = -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else if (async) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ctx->callback = callback;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ctx->context = context;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (dict->async_commits++ == 0) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict->io = io_add(dict->fd, IO_READ,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen dict_async_input, dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
d3fce898d31ad40b554c91f3035a7f4d7d52ed52Timo Sirainen } else {
a2d977362a01b38243e4840f15dd4f289a984a58Timo Sirainen /* sync commit, read reply */
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen line = client_dict_read_line(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (line == NULL)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = -1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else if (*line == DICT_PROTOCOL_REPLY_OK)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = 1;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else if (*line == DICT_PROTOCOL_REPLY_NOTFOUND)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen ret = 0;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen ret = -1;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (ret < 0 || !async) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_REMOVE(&dict->transactions, ctx);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_free(ctx);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return ret;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_rollback(struct dict_transaction_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (ctx->sent_begin) T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen query = t_strdup_printf("%c%u\n", DICT_PROTOCOL_CMD_ROLLBACK,
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen ctx->id);
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen (void)client_dict_send_transaction_query(ctx, query);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen DLLIST_REMOVE(&dict->transactions, ctx);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_free(ctx);
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen
28a311381d783cc06e56f9baf1cb9f25634cbfe4Timo Sirainen client_dict_add_timeout(dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_set(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *key, const char *value)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%u\t%s\t%s\n",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen DICT_PROTOCOL_CMD_SET, ctx->id,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen dict_client_escape(key),
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen dict_client_escape(value));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)client_dict_send_transaction_query(ctx, query);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenstatic void client_dict_unset(struct dict_transaction_context *_ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key)
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen{
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen struct client_dict_transaction_context *ctx =
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen (struct client_dict_transaction_context *)_ctx;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%u\t%s\n",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen DICT_PROTOCOL_CMD_UNSET, ctx->id,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen dict_client_escape(key));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)client_dict_send_transaction_query(ctx, query);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen}
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_atomic_inc(struct dict_transaction_context *_ctx,
a1295ce772f4765320a11a572595ce8eff37c343Timo Sirainen const char *key, long long diff)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen{
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict_transaction_context *ctx =
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const char *query;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%u\t%s\t%lld\n",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen DICT_PROTOCOL_CMD_ATOMIC_INC,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen ctx->id, dict_client_escape(key), diff);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)client_dict_send_transaction_query(ctx, query);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen}
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
419cf63077e755935ce105747d6ebc67b7d38a7fTimo Sirainenstruct dict dict_driver_client = {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen .name = "proxy",
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_init,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_deinit,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen client_dict_wait,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_lookup,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_iterate_init,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_iterate,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_iterate_deinit,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_transaction_init,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_transaction_commit,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_transaction_rollback,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_set,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen client_dict_unset,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen client_dict_atomic_inc
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen }
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen};