dict-memcached-ascii.c revision 75bb83681e30d6a86109bbafdfe6b513c11124bc
/* Copyright (c) 2008-2012 Dovecot authors, see the included COPYING memcached_ascii */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "dict-transaction-memory.h"
#include "dict-private.h"
#define MEMCACHED_DEFAULT_PORT 11211
#define DICT_USERNAME_SEPARATOR '/'
enum memcached_ascii_input_state {
/* GET: expecting VALUE or END */
/* SET/(APPEND+ADD): expecting STORED / NOT_STORED */
/* DELETE: expecting DELETED */
/* (INCR+ADD)/DECR: expecting number / NOT_FOUND / STORED / NOT_STORED */
};
struct memcached_ascii_connection {
struct connection conn;
struct memcached_ascii_dict *dict;
unsigned int reply_bytes_left;
bool value_received;
bool value_waiting_end;
};
struct memcached_ascii_dict_reply {
unsigned int reply_count;
void *context;
};
struct dict_memcached_ascii_commit_ctx {
struct memcached_ascii_dict *dict;
struct dict_transaction_memory_context *memctx;
void *context;
};
struct memcached_ascii_dict {
char *username, *key_prefix;
unsigned int port;
unsigned int timeout_msecs;
struct memcached_ascii_connection conn;
};
static struct connection_list *memcached_ascii_connections;
{
struct memcached_ascii_connection *conn =
(struct memcached_ascii_connection *)_conn;
const struct memcached_ascii_dict_reply *reply;
}
conn->reply_bytes_left = 0;
}
{
const unsigned char *data;
if (conn->reply_bytes_left > 0)
return FALSE;
/* finished. drop the trailing CRLF */
return TRUE;
}
{
const enum memcached_ascii_input_state *states;
const char *line, *p;
unsigned int count;
long long num;
if (conn->reply_bytes_left > 0) {
/* continue reading bulk reply */
if (!memcached_ascii_input_value(conn))
return 0;
} else if (conn->value_waiting_end) {
} else {
}
return 0;
if (count == 0) {
i_error("memcached_ascii: Unexpected input (expected nothing): %s",
line);
return -1;
}
switch (states[0]) {
/* VALUE <key> <flags> <bytes>
END */
break;
return memcached_ascii_input_reply_read(dict);
return 1;
break;
break;
return 1;
break;
return 1;
break;
return 1;
}
i_error("memcached_ascii: Unexpected input (state=%d): %s",
return -1;
}
{
struct memcached_ascii_dict_reply *replies;
unsigned int count;
int ret;
return ret;
/* finished a reply */
if (--replies[0].reply_count == 0) {
}
return 1;
}
{
struct memcached_ascii_connection *conn =
(struct memcached_ascii_connection *)_conn;
case 0:
return;
case -1:
return;
default:
break;
}
break;
}
}
}
{
}
{
i_error("memcached_ascii: Request timed out in %u.%03u secs",
}
{
int ret;
if (ret < 0)
break;
}
if (ret != 0)
break;
}
return ret < 0 ? -1 : 0;
}
{
int ret;
/* waiting for connection to finish */
if (ret < 0)
return -1;
}
if (memcached_ascii_wait_replies(dict) < 0)
return -1;
return 0;
}
{
i_error("memcached_ascii: connect(%s, %u) failed: %m",
}
}
static const struct connection_settings memcached_ascii_conn_set = {
};
static const struct connection_vfuncs memcached_ascii_conn_vfuncs = {
};
static const char *memcached_ascii_escape_username(const char *username)
{
const char *p;
for (p = username; *p != '\0'; p++) {
switch (*p) {
case DICT_USERNAME_SEPARATOR:
break;
case '\\':
break;
default:
str_append_c(str, *p);
}
}
}
static struct dict *
const char *username,
const char *base_dir ATTR_UNUSED)
{
struct memcached_ascii_dict *dict;
const char *const *args;
if (memcached_ascii_connections == NULL) {
}
i_unreached();
else {
/* escape the username */
}
} else {
}
}
}
{
struct memcached_ascii_dict *dict =
(struct memcached_ascii_dict *)_dict;
(void)memcached_ascii_wait(dict);
}
{
return 0;
i_error("memcached_ascii: Couldn't connect to %s:%u",
return -1;
}
}
return memcached_ascii_wait(dict);
}
static const char *
const char *key)
{
} else {
i_unreached();
}
return key;
}
static int
{
struct memcached_ascii_dict_reply *reply;
if (memcached_ascii_connect(dict) < 0)
return -1;
if (memcached_ascii_wait(dict) < 0)
return -1;
}
static int
{
int ret;
if (pool->datastack_pool)
else T_BEGIN {
} T_END;
return ret;
}
static struct dict_transaction_context *
{
struct dict_transaction_memory_context *ctx;
}
static void
const struct dict_transaction_memory_change *change)
{
case DICT_CHANGE_TYPE_SET:
break;
case DICT_CHANGE_TYPE_UNSET:
break;
case DICT_CHANGE_TYPE_APPEND:
/* we'd preferably want an append that always works, but
this kludge works for that too.. */
break;
case DICT_CHANGE_TYPE_INC:
/* same kludge as with append */
} else {
}
break;
}
}
static int
{
struct memcached_ascii_dict_reply *reply;
const struct dict_transaction_memory_change *changes;
unsigned int i, count, old_state_count;
if (memcached_ascii_connect(dict) < 0)
return -1;
} T_END;
return 1;
}
static int
bool async,
void *context)
{
struct dict_transaction_memory_context *ctx =
(struct dict_transaction_memory_context *)_ctx;
struct memcached_ascii_dict *dict =
int ret = 1;
if (memcached_ascii_wait(dict) < 0)
ret = -1;
}
}
return ret;
}
struct dict dict_driver_memcached_ascii = {
.name = "memcached_ascii",
{
NULL,
NULL,
NULL,
NULL,
}
};