bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING memcached_ascii */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "lib.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "array.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "str.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "istream.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "ostream.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "connection.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "dict-transaction-memory.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#include "dict-private.h"
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#define MEMCACHED_DEFAULT_PORT 11211
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#define MEMCACHED_DEFAULT_LOOKUP_TIMEOUT_MSECS (1000*30)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen#define DICT_USERNAME_SEPARATOR '/'
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenenum memcached_ascii_input_state {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* GET: expecting VALUE or END */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen MEMCACHED_INPUT_STATE_GET,
3fd02e831c32598deda589ae536fdaa4022d9750Aki Tuomi /* SET: expecting STORED / NOT_STORED */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen MEMCACHED_INPUT_STATE_STORED,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* DELETE: expecting DELETED */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen MEMCACHED_INPUT_STATE_DELETED,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* (INCR+ADD)/DECR: expecting number / NOT_FOUND / STORED / NOT_STORED */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen MEMCACHED_INPUT_STATE_INCRDECR
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstruct memcached_ascii_connection {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct connection conn;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen string_t *reply_str;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int reply_bytes_left;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen bool value_received;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen bool value_waiting_end;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstruct memcached_ascii_dict_reply {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int reply_count;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict_transaction_commit_callback_t *callback;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen void *context;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstruct dict_memcached_ascii_commit_ctx {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct dict_transaction_memory_context *memctx;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen string_t *str;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict_transaction_commit_callback_t *callback;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen void *context;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstruct memcached_ascii_dict {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct dict dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct ip_addr ip;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen char *username, *key_prefix;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int timeout_msecs;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen struct ioloop *ioloop, *prev_ioloop;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct timeout *to;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_connection conn;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(enum memcached_ascii_input_state) input_states;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct memcached_ascii_dict_reply) replies;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic struct connection_list *memcached_ascii_connections;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainenstatic void
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainenmemcached_ascii_callback(struct memcached_ascii_dict *dict,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const struct memcached_ascii_dict_reply *reply,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const struct dict_commit_result *result)
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen{
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen if (reply->callback != NULL) {
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen if (dict->prev_ioloop != NULL) {
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen /* Don't let callback see that we've created our
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen internal ioloop in case it wants to add some ios
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen or timeouts. */
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen current_ioloop = dict->prev_ioloop;
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen reply->callback(result, reply->context);
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen if (dict->prev_ioloop != NULL)
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen current_ioloop = dict->ioloop;
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen }
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen}
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenmemcached_ascii_disconnected(struct memcached_ascii_connection *conn,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char *reason)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen const struct dict_commit_result result = {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen DICT_COMMIT_RET_FAILED, reason
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen };
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const struct memcached_ascii_dict_reply *reply;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen connection_disconnect(&conn->conn);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (conn->dict->ioloop != NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen io_loop_stop(conn->dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen array_foreach(&conn->dict->replies, reply)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_callback(conn->dict, reply, &result);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_clear(&conn->dict->replies);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_clear(&conn->dict->input_states);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->reply_bytes_left = 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenstatic void memcached_ascii_conn_destroy(struct connection *_conn)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen{
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen struct memcached_ascii_connection *conn =
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen (struct memcached_ascii_connection *)_conn;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_disconnected(conn, connection_disconnect_reason(_conn));
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen}
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic bool memcached_ascii_input_value(struct memcached_ascii_connection *conn)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const unsigned char *data;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen size_t size;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen data = i_stream_get_data(conn->conn.input, &size);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (size > conn->reply_bytes_left)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen size = conn->reply_bytes_left;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->reply_bytes_left -= size;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_append_n(conn->reply_str, data, size);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_stream_skip(conn->conn.input, size);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (conn->reply_bytes_left > 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return FALSE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* finished. drop the trailing CRLF */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_truncate(conn->reply_str, str_len(conn->reply_str)-2);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->value_received = TRUE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return TRUE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_input_reply_read(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_connection *conn = &dict->conn;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const enum memcached_ascii_input_state *states;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const char *line, *p;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int count;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen long long num;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (conn->reply_bytes_left > 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* continue reading bulk reply */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (!memcached_ascii_input_value(conn))
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->value_waiting_end = TRUE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else if (conn->value_waiting_end) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->value_waiting_end = FALSE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_truncate(conn->reply_str, 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->value_received = FALSE;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen line = i_stream_next_line(conn->conn.input);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (line == NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen states = array_get(&dict->input_states, &count);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (count == 0) {
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen *error_r = t_strdup_printf(
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen "memcached_ascii: Unexpected input (expected nothing): %s", line);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen switch (states[0]) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case MEMCACHED_INPUT_STATE_GET:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* VALUE <key> <flags> <bytes>
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen END */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strncmp(line, "VALUE ", 6) == 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen p = strrchr(line, ' ');
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (str_to_uint(p+1, &conn->reply_bytes_left) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen conn->reply_bytes_left += 2; /* CRLF */
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen return memcached_ascii_input_reply_read(dict, error_r);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else if (strcmp(line, "END") == 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case MEMCACHED_INPUT_STATE_STORED:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strcmp(line, "STORED") != 0 &&
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen strcmp(line, "NOT_STORED") != 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case MEMCACHED_INPUT_STATE_DELETED:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strcmp(line, "DELETED") != 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case MEMCACHED_INPUT_STATE_INCRDECR:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strcmp(line, "NOT_FOUND") != 0 &&
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen strcmp(line, "STORED") != 0 &&
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen strcmp(line, "NOT_STORED") != 0 &&
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_to_llong(line, &num) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen *error_r = t_strdup_printf(
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen "memcached_ascii: Unexpected input (state=%d): %s",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen states[0], line);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_input_reply(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen const struct dict_commit_result result = {
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen DICT_COMMIT_RET_OK, NULL
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen };
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict_reply *replies;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int count;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen int ret;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if ((ret = memcached_ascii_input_reply_read(dict, error_r)) <= 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return ret;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* finished a reply */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_delete(&dict->input_states, 0, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen replies = array_get_modifiable(&dict->replies, &count);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(count > 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(replies[0].reply_count > 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (--replies[0].reply_count == 0) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_callback(dict, &replies[0], &result);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_delete(&dict->replies, 0, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic void memcached_ascii_conn_input(struct connection *_conn)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_connection *conn =
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen (struct memcached_ascii_connection *)_conn;
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char *error;
3d95a75a81478fe82ba7ef512f0f8e37748e445dTimo Sirainen int ret;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen switch (i_stream_read(_conn->input)) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case 0:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case -1:
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_disconnected(conn,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen i_stream_get_disconnect_reason(_conn->input));
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen default:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen while ((ret = memcached_ascii_input_reply(conn->dict, &error)) > 0) ;
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (ret < 0)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_disconnected(conn, error);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen io_loop_stop(conn->dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_input_wait(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen dict->prev_ioloop = current_ioloop;
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (dict->to != NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->to = io_loop_move_timeout(&dict->to);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_switch_ioloop(&dict->conn.conn);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen io_loop_run(dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen io_loop_set_current(dict->prev_ioloop);
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen dict->prev_ioloop = NULL;
5c5e738bcc6e50228bdadbf77a8ab16a2eb915bbTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (dict->to != NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->to = io_loop_move_timeout(&dict->to);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_switch_ioloop(&dict->conn.conn);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (dict->conn.conn.fd_in == -1) {
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen *error_r = "memcached_ascii: Communication failure";
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen return -1;
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen }
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic void memcached_ascii_input_timeout(struct memcached_ascii_dict *dict)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char *reason = t_strdup_printf(
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen "memcached_ascii: Request timed out in %u.%03u secs",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->timeout_msecs/1000, dict->timeout_msecs%1000);
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_disconnected(&dict->conn, reason);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_wait_replies(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
3d95a75a81478fe82ba7ef512f0f8e37748e445dTimo Sirainen int ret = 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->to = timeout_add(dict->timeout_msecs,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen memcached_ascii_input_timeout, dict);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen while (array_count(&dict->input_states) > 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(array_count(&dict->replies) > 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if ((ret = memcached_ascii_input_reply(dict, error_r)) != 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (ret < 0)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen memcached_ascii_disconnected(&dict->conn, *error_r);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen ret = memcached_ascii_input_wait(dict, error_r);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (ret != 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen timeout_remove(&dict->to);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return ret < 0 ? -1 : 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_wait(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen int ret;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(dict->conn.conn.fd_in != -1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (dict->conn.conn.input == NULL) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* waiting for connection to finish */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->to = timeout_add(dict->timeout_msecs,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen memcached_ascii_input_timeout, dict);
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen ret = memcached_ascii_input_wait(dict, error_r);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen timeout_remove(&dict->to);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (ret < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (memcached_ascii_wait_replies(dict, error_r) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(array_count(&dict->input_states) == 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(array_count(&dict->replies) == 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainenstatic void
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainenmemcached_ascii_conn_connected(struct connection *_conn, bool success)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_connection *conn = (struct memcached_ascii_connection *)_conn;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen if (!success) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_error("memcached_ascii: connect(%s, %u) failed: %m",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen net_ip2addr(&conn->dict->ip), conn->dict->port);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (conn->dict->ioloop != NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen io_loop_stop(conn->dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic const struct connection_settings memcached_ascii_conn_set = {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .input_max_size = (size_t)-1,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .output_max_size = (size_t)-1,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .client = TRUE
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic const struct connection_vfuncs memcached_ascii_conn_vfuncs = {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .destroy = memcached_ascii_conn_destroy,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .input = memcached_ascii_conn_input,
7db7fbea5d8a07463b625f93d69166d56018dadfTimo Sirainen .client_connected = memcached_ascii_conn_connected
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic const char *memcached_ascii_escape_username(const char *username)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const char *p;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen string_t *str = t_str_new(64);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen for (p = username; *p != '\0'; p++) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen switch (*p) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case DICT_USERNAME_SEPARATOR:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_append(str, "\\-");
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case '\\':
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_append(str, "\\\\");
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen default:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_append_c(str, *p);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return str_c(str);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
10399559650f552a23949772be79eb6a80198c5aTimo Sirainenstatic int
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenmemcached_ascii_dict_init(struct dict *driver, const char *uri,
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen const struct dict_settings *set,
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen struct dict **dict_r, const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const char *const *args;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct ioloop *old_ioloop = current_ioloop;
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen int ret = 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (memcached_ascii_connections == NULL) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen memcached_ascii_connections =
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_list_init(&memcached_ascii_conn_set,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen &memcached_ascii_conn_vfuncs);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict = i_new(struct memcached_ascii_dict, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (net_addr2ip("127.0.0.1", &dict->ip) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_unreached();
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->port = MEMCACHED_DEFAULT_PORT;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->timeout_msecs = MEMCACHED_DEFAULT_LOOKUP_TIMEOUT_MSECS;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->key_prefix = i_strdup("");
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen args = t_strsplit(uri, ":");
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen for (; *args != NULL; args++) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strncmp(*args, "host=", 5) == 0) {
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen if (net_addr2ip(*args+5, &dict->ip) < 0) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Invalid IP: %s",
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *args+5);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen ret = -1;
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else if (strncmp(*args, "port=", 5) == 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (net_str2port(*args+5, &dict->port) < 0) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Invalid port: %s",
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *args+5);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen ret = -1;
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else if (strncmp(*args, "prefix=", 7) == 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_free(dict->key_prefix);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->key_prefix = i_strdup(*args + 7);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else if (strncmp(*args, "timeout_msecs=", 14) == 0) {
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen if (str_to_uint(*args+14, &dict->timeout_msecs) < 0) {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf(
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen "Invalid timeout_msecs: %s", *args+14);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen ret = -1;
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else {
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *error_r = t_strdup_printf("Unknown parameter: %s",
eca38954bcf972618f6b85932a3690acbd2b673aTimo Sirainen *args);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen ret = -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen if (ret < 0) {
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen i_free(dict->key_prefix);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen i_free(dict);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen return -1;
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen }
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_init_client_ip(memcached_ascii_connections, &dict->conn.conn,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen &dict->ip, dict->port);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->dict = *driver;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->conn.reply_str = str_new(default_pool, 256);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->conn.dict = dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen if (strchr(set->username, DICT_USERNAME_SEPARATOR) == NULL)
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen dict->username = i_strdup(set->username);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen else {
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen /* escape the username */
39ea5717264668e2c7f9f7986eb821d21785f47fTimo Sirainen dict->username = i_strdup(memcached_ascii_escape_username(set->username));
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen }
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen i_array_init(&dict->input_states, 4);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen i_array_init(&dict->replies, 4);
8f2eb1ee9ec07661bd50275da99b5f351972a49aTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict->ioloop = io_loop_create();
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(old_ioloop);
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen *dict_r = &dict->dict;
10399559650f552a23949772be79eb6a80198c5aTimo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic void memcached_ascii_dict_deinit(struct dict *_dict)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict =
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen (struct memcached_ascii_dict *)_dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct ioloop *old_ioloop = current_ioloop;
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char *error;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (array_count(&dict->input_states) > 0) {
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (memcached_ascii_wait(dict, &error) < 0)
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen i_error("%s", error);
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_deinit(&dict->conn.conn);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(dict->ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen io_loop_destroy(&dict->ioloop);
35f3b7e05afecacd0332c210c6e253911c2813d8Timo Sirainen io_loop_set_current(old_ioloop);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_free(&dict->conn.reply_str);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_free(&dict->replies);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_free(&dict->input_states);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_free(dict->key_prefix);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_free(dict->username);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_free(dict);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (memcached_ascii_connections->connections == NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen connection_list_deinit(&memcached_ascii_connections);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenstatic int memcached_ascii_connect(struct memcached_ascii_dict *dict,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (dict->conn.conn.input != NULL)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (dict->conn.conn.fd_in == -1) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (connection_client_connect(&dict->conn.conn) < 0) {
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen *error_r = t_strdup_printf(
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen "memcached_ascii: Couldn't connect to %s:%u",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen net_ip2addr(&dict->ip), dict->port);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen return memcached_ascii_wait(dict, error_r);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic const char *
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenmemcached_ascii_dict_get_full_key(struct memcached_ascii_dict *dict,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const char *key)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (strncmp(key, DICT_PATH_SHARED, strlen(DICT_PATH_SHARED)) == 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key += strlen(DICT_PATH_SHARED);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen else if (strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE)) == 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key = t_strdup_printf("%s%c%s", dict->username,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen DICT_USERNAME_SEPARATOR,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key + strlen(DICT_PATH_PRIVATE));
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_unreached();
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (*dict->key_prefix != '\0')
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key = t_strconcat(dict->key_prefix, key, NULL);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return key;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic int
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainenmemcached_ascii_dict_lookup(struct dict *_dict, pool_t pool, const char *key,
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen const char **value_r, const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen struct memcached_ascii_dict *dict = (struct memcached_ascii_dict *)_dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict_reply *reply;
8f9a18189f01448267100fa54c3b4bb8639a1a56Timo Sirainen enum memcached_ascii_input_state state = MEMCACHED_INPUT_STATE_GET;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (memcached_ascii_connect(dict, error_r) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key = memcached_ascii_dict_get_full_key(dict, key);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen o_stream_nsend_str(dict->conn.conn.output,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen t_strdup_printf("get %s\r\n", key));
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_append(&dict->input_states, &state, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply = array_append_space(&dict->replies);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply->reply_count = 1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
b5052fbfdbc2678cc8f12899afe55c998f43b740Timo Sirainen if (memcached_ascii_wait(dict, error_r) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen *value_r = p_strdup(pool, str_c(dict->conn.reply_str));
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return dict->conn.value_received ? 1 : 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic struct dict_transaction_context *
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenmemcached_ascii_transaction_init(struct dict *_dict)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct dict_transaction_memory_context *ctx;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen pool_t pool;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen pool = pool_alloconly_create("file dict transaction", 2048);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen ctx = p_new(pool, struct dict_transaction_memory_context, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict_transaction_memory_init(ctx, _dict, pool);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return &ctx->ctx;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic void
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenmemcached_send_change(struct dict_memcached_ascii_commit_ctx *ctx,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const struct dict_transaction_memory_change *change)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen enum memcached_ascii_input_state state;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const char *key, *value;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key = memcached_ascii_dict_get_full_key(ctx->dict, change->key);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_truncate(ctx->str, 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen switch (change->type) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case DICT_CHANGE_TYPE_SET:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen state = MEMCACHED_INPUT_STATE_STORED;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_printfa(ctx->str, "set %s 0 0 %"PRIuSIZE_T"\r\n%s\r\n",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key, strlen(change->value.str), change->value.str);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case DICT_CHANGE_TYPE_UNSET:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen state = MEMCACHED_INPUT_STATE_DELETED;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_printfa(ctx->str, "delete %s\r\n", key);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen case DICT_CHANGE_TYPE_INC:
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen state = MEMCACHED_INPUT_STATE_INCRDECR;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (change->value.diff > 0) {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_printfa(ctx->str, "incr %s %lld\r\n",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key, change->value.diff);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_append(&ctx->dict->input_states, &state, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen /* same kludge as with append */
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen value = t_strdup_printf("%lld", change->value.diff);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_printfa(ctx->str, "add %s 0 0 %u\r\n%s\r\n",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key, (unsigned int)strlen(value), value);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } else {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_printfa(ctx->str, "decr %s %lld\r\n",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen key, -change->value.diff);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen break;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen array_append(&ctx->dict->input_states, &state, 1);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen o_stream_nsend(ctx->dict->conn.conn.output,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen str_data(ctx->str), str_len(ctx->str));
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstatic int
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainenmemcached_ascii_transaction_send(struct dict_memcached_ascii_commit_ctx *ctx,
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen const char **error_r)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict = ctx->dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict_reply *reply;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen const struct dict_transaction_memory_change *changes;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen unsigned int i, count, old_state_count;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (memcached_ascii_connect(dict, error_r) < 0)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen return -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen old_state_count = array_count(&dict->input_states);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen changes = array_get(&ctx->memctx->changes, &count);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen i_assert(count > 0);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen o_stream_cork(dict->conn.conn.output);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen for (i = 0; i < count; i++) T_BEGIN {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen memcached_send_change(ctx, &changes[i]);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen } T_END;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen o_stream_uncork(dict->conn.conn.output);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply = array_append_space(&dict->replies);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply->callback = ctx->callback;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply->context = ctx->context;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen reply->reply_count = array_count(&dict->input_states) - old_state_count;
b2d3b5298be1820233205242c772804037555a54Timo Sirainen return 0;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainenstatic void
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenmemcached_ascii_transaction_commit(struct dict_transaction_context *_ctx,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen bool async,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen dict_transaction_commit_callback_t *callback,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen void *context)
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen{
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct dict_transaction_memory_context *ctx =
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen (struct dict_transaction_memory_context *)_ctx;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct memcached_ascii_dict *dict =
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen (struct memcached_ascii_dict *)_ctx->dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen struct dict_memcached_ascii_commit_ctx commit_ctx;
9a382894724292e2af60ef94fc471d761f45e5d5Timo Sirainen struct dict_commit_result result = { DICT_COMMIT_RET_OK, NULL };
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen if (_ctx->changed) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&commit_ctx);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen commit_ctx.dict = dict;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen commit_ctx.memctx = ctx;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen commit_ctx.callback = callback;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen commit_ctx.context = context;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen commit_ctx.str = str_new(default_pool, 128);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen result.ret = memcached_ascii_transaction_send(&commit_ctx, &result.error);
b2d3b5298be1820233205242c772804037555a54Timo Sirainen str_free(&commit_ctx.str);
b2d3b5298be1820233205242c772804037555a54Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (async && result.ret == 0) {
b2d3b5298be1820233205242c772804037555a54Timo Sirainen pool_unref(&ctx->pool);
c2a66e7950cb4d3fc4d68e4480ea8f39bdd7c871Timo Sirainen return;
b2d3b5298be1820233205242c772804037555a54Timo Sirainen }
b2d3b5298be1820233205242c772804037555a54Timo Sirainen
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (result.ret == 0) {
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen if (memcached_ascii_wait(dict, &result.error) < 0)
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen result.ret = -1;
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
661998e2ccd772ad92a9d4a75cb712692a8c94b3Timo Sirainen callback(&result, context);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen pool_unref(&ctx->pool);
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen}
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainenstruct dict dict_driver_memcached_ascii = {
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen .name = "memcached_ascii",
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen {
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .init = memcached_ascii_dict_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .deinit = memcached_ascii_dict_deinit,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .lookup = memcached_ascii_dict_lookup,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_init = memcached_ascii_transaction_init,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_commit = memcached_ascii_transaction_commit,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .transaction_rollback = dict_transaction_memory_rollback,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .set = dict_transaction_memory_set,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .unset = dict_transaction_memory_unset,
ade5567577dadb0b275c840208d3ad21a9f00a36Timo Sirainen .atomic_inc = dict_transaction_memory_atomic_inc,
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen }
75bb83681e30d6a86109bbafdfe6b513c11124bcTimo Sirainen};