dict-client.c revision 3954326e793bdef1e94e0ad781ed6cc7e48beebb
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *uri;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *transactions;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict_transaction_context *prev, *next;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen /* for async commits */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen unsigned int id;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_connect(struct client_dict *dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenconst char *dict_client_escape(const char *src)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *p;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* first do a quick lookup to see if there's anything to escape.
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen probably not. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\0')
7bf6a25a58184d3ff4714d76a402d61a0cca2c52Timo Sirainen for (; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen switch (*p) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenconst char *dict_client_unescape(const char *src)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen const char *p;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* first do a quick lookup to see if there's anything to unescape.
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen probably not. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\001')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p == '\0')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen for (; *p != '\0'; p++) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (*p != '\001')
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen switch (*p) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_send_query(struct client_dict *dict, const char *query)
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen /* not connected currently */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Send failed */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* we're trying to send hello, don't try to reconnect */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Reconnect and try again. */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainenclient_dict_transaction_send_begin(struct client_dict_transaction_context *ctx)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%u\n", DICT_PROTOCOL_CMD_BEGIN,
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainenclient_dict_send_transaction_query(struct client_dict_transaction_context *ctx,
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen struct client_dict *dict = (struct client_dict *)ctx->ctx.dict;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (client_dict_transaction_send_begin(ctx) < 0)
e080054d7df103a9b6be62a476cbee18261acf6cTimo Sirainen if (ctx->connect_counter != dict->connect_counter || ctx->failed)
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen /* not connected, this'll fail */
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen if (o_stream_send_str(dict->output, query) < 0 ||
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen /* Send failed. Our transactions have died, so don't even try
684cbcce30cc97340ee43240de5c0d236c917d29Timo Sirainen to re-send the command */
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic struct client_dict_transaction_context *
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_find(struct client_dict *dict, unsigned int id)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen for (ctx = dict->transactions; ctx != NULL; ctx = ctx->next) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_finish_transaction(struct client_dict *dict,
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("dict-client: Unknown transaction id %u", id);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic int client_dict_read_one_line(struct client_dict *dict, char **line_r)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen unsigned int id;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen while ((line = i_stream_next_line(dict->input)) == NULL) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("read(%s) failed: Remote disconnected",
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("read(%s) returned too much data", dict->path);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (*line == DICT_PROTOCOL_REPLY_ASYNC_COMMIT) {
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen i_error("dict-client: Invalid async commit line: %s",
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen client_dict_finish_transaction(dict, id, ret);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic char *client_dict_read_line(struct client_dict *dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen while (client_dict_read_one_line(dict, &line) == 0)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_connect(struct client_dict *dict)
0b15bc85459ef4fea30ac1f8903af48dd6d5f8e2Timo Sirainen /* Try again later */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("net_connect_unix(%s) failed: %m", dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* Dictionary lookups are blocking */
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen dict->input = i_stream_create_fd(dict->fd, (size_t)-1, FALSE);
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen dict->output = o_stream_create_fd(dict->fd, 4096, FALSE);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen query = t_strdup_printf("%c%u\t%u\t%d\t%s\t%s\n",
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen if (client_dict_send_query(dict, query) < 0) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_disconnect(struct client_dict *dict)
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,
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen /* uri = [<path>] ":" <uri> */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen pool = pool_alloconly_create("client dict", 1024);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* path given */
9844b5359f5cab77e4c31a7ac9e4a60a0073929eTimo Sirainen dict->path = p_strdup_until(pool, uri, dest_uri);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_deinit(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic int client_dict_wait(struct dict *_dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen if (client_dict_read_one_line(dict, &line) < 0) {
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_lookup(struct dict *_dict, pool_t pool,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%s\n", DICT_PROTOCOL_CMD_LOOKUP,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* read reply */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = p_strdup(pool, dict_client_unescape(line + 1));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen return *line == DICT_PROTOCOL_REPLY_NOTFOUND ? 0 : -1;
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenclient_dict_iterate_init(struct dict *_dict, const char *path,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_panic("dict-client: Only one iteration supported");
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_iterate_context, 1);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx->pool = pool_alloconly_create("client dict iteration", 512);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen query = t_strdup_printf("%c%d\t%s\n", DICT_PROTOCOL_CMD_ITERATE,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic int client_dict_iterate(struct dict_iterate_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* read next reply */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* end of iteration */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* line contains key \t value */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen /* broken protocol */
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen i_error("dict client (%s) sent broken reply", dict->path);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *key_r = p_strdup(ctx->pool, dict_client_unescape(line));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen *value_r = p_strdup(ctx->pool, dict_client_unescape(value));
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_iterate_deinit(struct dict_iterate_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_init(struct dict *_dict)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen struct client_dict *dict = (struct client_dict *)_dict;
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen ctx = i_new(struct client_dict_transaction_context, 1);
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenstatic void dict_async_input(struct client_dict *dict)
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainenclient_dict_transaction_commit(struct 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 if (ctx->sent_begin && !ctx->failed) T_BEGIN {
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen if (client_dict_send_transaction_query(ctx, query) < 0)
a2d977362a01b38243e4840f15dd4f289a984a58Timo Sirainen /* sync commit, read reply */
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen else if (*line == DICT_PROTOCOL_REPLY_NOTFOUND)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenclient_dict_transaction_rollback(struct dict_transaction_context *_ctx)
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
3954326e793bdef1e94e0ad781ed6cc7e48beebbTimo Sirainen struct client_dict *dict = (struct client_dict *)_ctx->dict;
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen query = t_strdup_printf("%c%u\n", DICT_PROTOCOL_CMD_ROLLBACK,
4210fac11e936f7edd6f3deecd1b23466534ce6aTimo Sirainen (void)client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_set(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)client_dict_send_transaction_query(ctx, query);
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainenstatic void client_dict_unset(struct dict_transaction_context *_ctx,
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen const char *key)
92d1458b00f4f236c4cec96a696253d3bbf8b05aTimo Sirainen (struct client_dict_transaction_context *)_ctx;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen (void)client_dict_send_transaction_query(ctx, query);
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainenstatic void client_dict_atomic_inc(struct dict_transaction_context *_ctx,
ff52f5c52ee6a4c8a9c79964d32b5d0ff0ae92e6Timo Sirainen (struct client_dict_transaction_context *)_ctx;