dict-memcached.c revision 8f9a18189f01448267100fa54c3b4bb8639a1a56
/* Copyright (c) 2013-2016 Dovecot authors, see the included COPYING memcached */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "istream.h"
#include "ostream.h"
#include "connection.h"
#include "dict-private.h"
#define MEMCACHED_DEFAULT_PORT 11211
/* we need only very limited memcached functionality, so just define the binary
protocol ourself instead requiring protocol_binary.h */
#define MEMCACHED_REQUEST_HDR_MAGIC 0x80
#define MEMCACHED_REPLY_HDR_MAGIC 0x81
#define MEMCACHED_REQUEST_HDR_LENGTH 24
#define MEMCACHED_REPLY_HDR_LENGTH 24
#define MEMCACHED_CMD_GET 0x00
#define MEMCACHED_DATA_TYPE_RAW 0x00
enum memcached_response {
MEMCACHED_RESPONSE_OK = 0x0000,
MEMCACHED_RESPONSE_NOTFOUND = 0x0001,
MEMCACHED_RESPONSE_INTERNALERROR= 0x0084,
MEMCACHED_RESPONSE_BUSY = 0x0085,
MEMCACHED_RESPONSE_TEMPFAILURE = 0x0086
};
struct memcached_connection {
struct connection conn;
struct memcached_dict *dict;
struct {
const unsigned char *value;
unsigned int value_len;
enum memcached_response status;
bool reply_received;
} reply;
};
struct memcached_dict {
char *key_prefix;
unsigned int timeout_msecs;
struct memcached_connection conn;
bool connected;
};
static struct connection_list *memcached_connections;
{
}
{
const unsigned char *data;
if (size < MEMCACHED_REPLY_HDR_LENGTH)
return 0;
if (data[0] != MEMCACHED_REPLY_HDR_MAGIC) {
i_error("memcached: Invalid reply magic: %u != %u",
return -1;
}
/* we haven't read the whole response yet */
return 0;
}
if (data_type != MEMCACHED_DATA_TYPE_RAW) {
i_error("memcached: Unsupported data type: %u != %u",
data[0], MEMCACHED_DATA_TYPE_RAW);
return -1;
}
return -1;
}
return 1;
}
{
case 0:
return;
case -1:
return;
default:
break;
}
if (memcached_input_get(conn) < 0)
}
{
struct memcached_connection *conn =
(struct memcached_connection *)_conn;
if (!success) {
i_error("memcached: connect(%s, %u) failed: %m",
} else {
}
}
static const struct connection_settings memcached_conn_set = {
};
static const struct connection_vfuncs memcached_conn_vfuncs = {
};
static int
{
struct memcached_dict *dict;
const char *const *args;
int ret = 0;
if (memcached_connections == NULL) {
}
i_unreached();
*args+5);
ret = -1;
}
*args+5);
ret = -1;
}
ret = -1;
}
} else {
*args);
ret = -1;
}
}
if (ret < 0) {
return -1;
}
return 0;
}
{
}
{
i_error("memcached: Lookup timed out in %u.%03u secs",
}
{
}
{
unsigned int key_len;
else {
i_error("memcached: Only shared keys supported currently");
return -1;
}
if (key_len > 0xffff) {
i_error("memcached: Key is too long (%u bytes): %s",
return -1;
}
i_error("memcached: Couldn't connect to %s:%u",
} else {
/* wait for connection */
}
}
timeout_remove(&to);
}
/* we failed in some way. make sure we disconnect since the
connection state isn't known anymore */
return -1;
}
case MEMCACHED_RESPONSE_OK:
return 1;
return 0;
return -1;
case MEMCACHED_RESPONSE_BUSY:
return -1;
return -1;
}
i_error("memcached: Lookup(%s) failed: Error code=%u",
return -1;
}
struct dict dict_driver_memcached = {
.name = "memcached",
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
}
};