return response_handler(cookie, header, (void*)&response);
}
-struct memcached_binary_protocol_callback_st interface_v0_impl= {
+memcached_binary_protocol_callback_st interface_v0_impl= {
.interface_version= 0,
.interface.v0.comcode[PROTOCOL_BINARY_CMD_GET]= get_command_handler,
.interface.v0.comcode[PROTOCOL_BINARY_CMD_SET]= set_command_handler,
return response_handler(cookie, version, (uint32_t)strlen(version));
}
-struct memcached_binary_protocol_callback_st interface_v1_impl= {
+memcached_binary_protocol_callback_st interface_v1_impl= {
.interface_version= 1,
.interface.v1= {
.add= add_handler,
#include <libmemcached/byteorder.h>
#include "storage.h"
-extern struct memcached_binary_protocol_callback_st interface_v0_impl;
-extern struct memcached_binary_protocol_callback_st interface_v1_impl;
+extern memcached_binary_protocol_callback_st interface_v0_impl;
+extern memcached_binary_protocol_callback_st interface_v1_impl;
static int server_sockets[1024];
static int num_server_sockets= 0;
{
bool port_specified= false;
int cmd;
- struct memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
+ memcached_binary_protocol_callback_st *interface= &interface_v0_impl;
while ((cmd= getopt(argc, argv, "v1p:?")) != EOF)
{
assert(c != NULL);
fds[max_poll].events= 0;
- switch (memcached_protocol_client_work(c))
- {
- case WRITE_EVENT:
- case READ_WRITE_EVENT:
+ memcached_protocol_event_t events= memcached_protocol_client_work(c);
+ if (events & MEMCACHED_PROTOCOL_WRITE_EVENT)
fds[max_poll].events= POLLOUT;
- /* FALLTHROUGH */
- case READ_EVENT:
- fds[max_poll].events |= POLLIN;
- break;
- case ERROR_EVENT:
- default: /* ERROR or unknown state.. close */
+
+ if (events & MEMCACHED_PROTOCOL_READ_EVENT)
+ fds[max_poll].events= POLLIN;
+
+ if (!(events & MEMCACHED_PROTOCOL_PAUSE_EVENT ||
+ fds[max_poll].events != 0))
+ {
memcached_protocol_client_destroy(c);
close(fds[x].fd);
fds[x].events= 0;
PROTOCOL_BINARY_RESPONSE_DELTA_BADVAL = 0x06,
PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND = 0x81,
PROTOCOL_BINARY_RESPONSE_ENOMEM = 0x82,
- PROTOCOL_BINARY_RESPONSE_EIO = 0xff
+
+ PROTOCOL_BINARY_RESPONSE_PAUSE = 0xfe00,
+ PROTOCOL_BINARY_RESPONSE_EIO = 0xff00
} protocol_binary_response_status;
/**
static uint16_t parse_ascii_key(char **start)
{
uint16_t len= 0;
- char *c = *start;
+ char *c= *start;
/* Strip leading whitespaces */
while (isspace(*c))
{
* @return status of the spool operation
*/
static protocol_binary_response_status
-spool_string(struct memcached_protocol_client_st *client, const char *text)
+spool_string(memcached_protocol_client_st *client, const char *text)
{
return client->root->spool(client, text, strlen(text));
}
* format of the command being sent
* @param client the client to send the message to
*/
-static void send_command_usage(struct memcached_protocol_client_st *client)
+static void send_command_usage(memcached_protocol_client_st *client)
{
const char *errmsg[]= {
[GET_CMD]= "CLIENT_ERROR: Syntax error: get <key>*\r\n",
const void *text,
uint32_t textlen)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
spool_string(client, "VERSION ");
client->root->spool(client, text, textlen);
spool_string(client, "\r\n");
uint32_t flags,
uint64_t cas)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
char buffer[300];
strcpy(buffer, "VALUE ");
- const char *source = key;
- char *dest = buffer + 6;
+ const char *source= key;
+ char *dest= buffer + 6;
for (int x= 0; x < keylen; ++x)
{
if (*source != '\0' && !isspace(*source) && !iscntrl(*source))
{
- *dest = *source;
+ *dest= *source;
}
else
{
uint32_t bodylen)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (key != NULL)
{
* @param buffer the complete get(s) command
* @param end the last character in the command
*/
-static void ascii_process_gets(struct memcached_protocol_client_st *client,
+static void ascii_process_gets(memcached_protocol_client_st *client,
char *buffer, char *end)
{
char *key= buffer;
}
/* zero-terminate it for easier parsing later on */
- *str = '\0';
+ *str= '\0';
++str;
/* Is the vector full? */
while (start < end)
{
if (*start == '\0')
- *start = ' ';
+ *start= ' ';
++start;
}
const char *cmd;
size_t len;
enum ascii_cmd cc;
- } commands[] = {
+ } commands[]= {
{ .cmd= "get", .len= 3, .cc= GET_CMD },
{ .cmd= "gets", .len= 4, .cc= GETS_CMD },
{ .cmd= "set", .len= 3, .cc= SET_CMD },
* @param tokens the command as a vector
* @param ntokens the number of items in the vector
*/
-static void process_delete(struct memcached_protocol_client_st *client,
+static void process_delete(memcached_protocol_client_st *client,
char **tokens, int ntokens)
{
char *key= tokens[1];
}
}
-static void process_arithmetic(struct memcached_protocol_client_st *client,
+static void process_arithmetic(memcached_protocol_client_st *client,
char **tokens, int ntokens)
{
char *key= tokens[1];
uint64_t cas;
uint64_t result;
- uint64_t delta = strtoull(tokens[2], NULL, 10);
+ uint64_t delta= strtoull(tokens[2], NULL, 10);
protocol_binary_response_status rval;
if (client->ascii_command == INCR_CMD)
* @param key pointer to the first character after "stats"
* @param end pointer to the "\n"
*/
-static void process_stats(struct memcached_protocol_client_st *client,
+static void process_stats(memcached_protocol_client_st *client,
char *key, char *end)
{
if (client->root->callback->interface.v1.stat == NULL)
ascii_stat_response_handler);
}
-static void process_version(struct memcached_protocol_client_st *client,
+static void process_version(memcached_protocol_client_st *client,
char **tokens, int ntokens)
{
(void)tokens;
ascii_version_response_handler);
}
-static void process_flush(struct memcached_protocol_client_st *client,
+static void process_flush(memcached_protocol_client_st *client,
char **tokens, int ntokens)
{
if (ntokens > 2)
uint32_t timeout= 0;
if (ntokens == 2)
{
- timeout = (uint32_t)strtoul(tokens[1], NULL, 10);
+ timeout= (uint32_t)strtoul(tokens[1], NULL, 10);
}
protocol_binary_response_status rval;
* 0 storage command completed, continue processing
* 1 We need more data, so just go ahead and wait for more!
*/
-static inline int process_storage_command(struct memcached_protocol_client_st *client,
+static inline int process_storage_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return -1;
}
- uint32_t flags = (uint32_t)strtoul(tokens[2], NULL, 10);
- uint32_t timeout = (uint32_t)strtoul(tokens[3], NULL, 10);
- unsigned long nbytes = strtoul(tokens[4], NULL, 10);
+ uint32_t flags= (uint32_t)strtoul(tokens[2], NULL, 10);
+ uint32_t timeout= (uint32_t)strtoul(tokens[3], NULL, 10);
+ unsigned long nbytes= strtoul(tokens[4], NULL, 10);
/* Do we have all data? */
- unsigned long need = nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
+ unsigned long need= nbytes + (unsigned long)((*end - start) + 1) + 2; /* \n\r\n */
if ((ssize_t)need > length)
{
/* Keep on reading */
return 1;
}
- void *data = (*end) + 1;
+ void *data= (*end) + 1;
uint64_t cas= 0;
uint64_t result_cas;
protocol_binary_response_status rval;
timeout, &result_cas);
break;
case CAS_CMD:
- cas = strtoull(tokens[5], NULL, 10);
+ cas= strtoull(tokens[5], NULL, 10);
/* FALLTHROUGH */
case REPLACE_CMD:
rval= client->root->callback->interface.v1.replace(client, key,
return 0;
}
-static int process_cas_command(struct memcached_protocol_client_st *client,
+static int process_cas_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return process_storage_command(client, tokens, ntokens, start, end, length);
}
-static int process_set_command(struct memcached_protocol_client_st *client,
+static int process_set_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return process_storage_command(client, tokens, ntokens, start, end, length);
}
-static int process_add_command(struct memcached_protocol_client_st *client,
+static int process_add_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return process_storage_command(client, tokens, ntokens, start, end, length);
}
-static int process_replace_command(struct memcached_protocol_client_st *client,
+static int process_replace_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return process_storage_command(client, tokens, ntokens, start, end, length);
}
-static int process_append_command(struct memcached_protocol_client_st *client,
+static int process_append_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
return process_storage_command(client, tokens, ntokens, start, end, length);
}
-static int process_prepend_command(struct memcached_protocol_client_st *client,
+static int process_prepend_command(memcached_protocol_client_st *client,
char **tokens, int ntokens, char *start,
char **end, ssize_t length)
{
* a optimal ascii support, I just convert the ASCII commands to the binary
* protocol and calls back into the command handlers for the binary protocol ;)
*/
-enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
{
char *ptr= (char*)client->root->input_buffer;
*endptr= ptr;
if (end == NULL)
{
*endptr= ptr;
- return READ_EVENT;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
}
client->ascii_command= ascii_to_cmd(ptr, (size_t)(*length));
if (client->root->callback->interface.v1.quit != NULL)
client->root->callback->interface.v1.quit(client);
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
break;
}
if (error == -1)
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
else if (error == 1)
- return READ_EVENT;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
}
/* Move past \n */
ptr= end;
} while (*length > 0);
- *endptr = ptr;
- return READ_EVENT;
+ *endptr= ptr;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
}
#define LIBMEMCACHED_PROTOCOL_ASCII_HANDLER_H
LIBMEMCACHED_LOCAL
-enum MEMCACHED_PROTOCOL_EVENT memcached_ascii_protocol_process_data(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+memcached_protocol_event_t memcached_ascii_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
#endif
protocol_binary_request_header *request,
protocol_binary_response_header *response)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->pedantic &&
!memcached_binary_protocol_pedantic_check_response(request, response))
uint32_t flags,
uint64_t cas) {
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
uint8_t opcode= client->current_command->request.opcode;
if (opcode == PROTOCOL_BINARY_CMD_GET || opcode == PROTOCOL_BINARY_CMD_GETQ)
};
protocol_binary_response_status rval;
- const protocol_binary_response_status success = PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
(rval= client->root->spool(client, key, keylen)) != success ||
(rval= client->root->spool(client, body, bodylen)) != success)
const void *body,
uint32_t bodylen) {
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
protocol_binary_response_no_extras response= {
.message.header.response= {
};
protocol_binary_response_status rval;
- const protocol_binary_response_status success = PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
(rval= client->root->spool(client, key, keylen)) != success ||
(rval= client->root->spool(client, body, bodylen)) != success)
const void *text,
uint32_t textlen) {
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
protocol_binary_response_no_extras response= {
.message.header.response= {
};
protocol_binary_response_status rval;
- const protocol_binary_response_status success = PROTOCOL_BINARY_RESPONSE_SUCCESS;
+ const protocol_binary_response_status success= PROTOCOL_BINARY_RESPONSE_SUCCESS;
if ((rval= client->root->spool(client, response.bytes, sizeof(response.bytes))) != success ||
(rval= client->root->spool(client, text, textlen)) != success)
{
{
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.add != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.decrement != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
.cas= ntohll(cas),
.bodylen= htonl(8)
},
- .body.value = htonll(result)
+ .body.value= htonll(result)
}
};
rval= response_handler(cookie, header, (void*)&response);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.delete != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.flush != NULL)
{
protocol_binary_request_flush *flush= (void*)header;
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.get != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.increment != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
.cas= ntohll(cas),
.bodylen= htonl(8)
},
- .body.value = htonll(result)
+ .body.value= htonll(result)
}
};
protocol_binary_request_header *header,
memcached_binary_protocol_raw_response_handler response_handler)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.noop != NULL)
{
client->root->callback->interface.v1.noop(cookie);
}
protocol_binary_response_no_extras response= {
- .message = {
- .header.response = {
- .magic = PROTOCOL_BINARY_RES,
+ .message= {
+ .header.response= {
+ .magic= PROTOCOL_BINARY_RES,
.opcode= PROTOCOL_BINARY_CMD_NOOP,
.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
.opaque= header->request.opaque,
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.append != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.prepend != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
protocol_binary_request_header *header,
memcached_binary_protocol_raw_response_handler response_handler)
{
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.quit != NULL)
{
client->root->callback->interface.v1.quit(cookie);
}
protocol_binary_response_no_extras response= {
- .message = {
- .header.response = {
+ .message= {
+ .header.response= {
.magic= PROTOCOL_BINARY_RES,
.opcode= PROTOCOL_BINARY_CMD_QUIT,
.status= htons(PROTOCOL_BINARY_RESPONSE_SUCCESS),
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.replace != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.set != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)response_handler;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.stat != NULL)
{
uint16_t keylen= ntohs(header->request.keylen);
(void)header;
protocol_binary_response_status rval;
- struct memcached_protocol_client_st *client= (void*)cookie;
+ memcached_protocol_client_st *client= (void*)cookie;
if (client->root->callback->interface.v1.version != NULL)
{
rval= client->root->callback->interface.v1.version(cookie,
* @return true if success or false if a fatal error occured so that the
* connection should be shut down.
*/
-static bool execute_command(struct memcached_protocol_client_st *client, protocol_binary_request_header *header)
+static protocol_binary_response_status execute_command(memcached_protocol_client_st *client, protocol_binary_request_header *header)
{
if (client->root->pedantic &&
memcached_binary_protocol_pedantic_check_request(header))
}
if (rval != PROTOCOL_BINARY_RESPONSE_SUCCESS &&
- rval != PROTOCOL_BINARY_RESPONSE_EIO)
+ rval != PROTOCOL_BINARY_RESPONSE_EIO &&
+ rval != PROTOCOL_BINARY_RESPONSE_PAUSE)
{
protocol_binary_response_no_extras response= {
.message= {
client->root->callback->post_execute(client, header);
}
- return rval != PROTOCOL_BINARY_RESPONSE_EIO;
+ return rval;
}
/*
** "PROTOECTED" INTERFACE
** **********************************************************************
*/
-enum MEMCACHED_PROTOCOL_EVENT memcached_binary_protocol_process_data(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr)
{
/* try to parse all of the received packets */
protocol_binary_request_header *header;
if (header->request.magic != (uint8_t)PROTOCOL_BINARY_REQ)
{
client->error= EINVAL;
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
ssize_t len= *length;
(len >= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen))))
{
/* I have the complete package */
- client->current_command = header;
- if (!execute_command(client, header))
+ client->current_command= header;
+ protocol_binary_response_status rv= execute_command(client, header);
+
+ if (rv == PROTOCOL_BINARY_RESPONSE_EIO)
{
*length= len;
*endptr= (void*)header;
- return ERROR_EVENT;
- }
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
+ } else if (rv == PROTOCOL_BINARY_RESPONSE_PAUSE)
+ return MEMCACHED_PROTOCOL_PAUSE_EVENT;
ssize_t total= (ssize_t)(sizeof(*header) + ntohl(header->request.bodylen));
len -= total;
header= (void*)client->root->input_buffer;
}
}
+ *length= len;
+ *endptr= (void*)header;
}
- *length= len;
- *endptr= (void*)header;
-
- return READ_EVENT;
+ return MEMCACHED_PROTOCOL_READ_EVENT;
}
/*
** PUBLIC INTERFACE
** **********************************************************************
*/
-struct memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(struct memcached_protocol_st *instance)
+memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance)
{
return instance->callback;
}
-void memcached_binary_protocol_set_callbacks(struct memcached_protocol_st *instance, struct memcached_binary_protocol_callback_st *callback)
+void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback)
{
instance->callback= callback;
}
return raw_response_handler;
}
-void memcached_binary_protocol_set_pedantic(struct memcached_protocol_st *instance, bool enable)
+void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable)
{
instance->pedantic= enable;
}
-bool memcached_binary_protocol_get_pedantic(struct memcached_protocol_st *instance)
+bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance)
{
return instance->pedantic;
}
#define LIBMEMCACHED_PROTOCOL_BINARY_HANDLER_H
LIBMEMCACHED_LOCAL
-bool memcached_binary_protocol_pedantic_check_request(protocol_binary_request_header *request);
+bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request);
LIBMEMCACHED_LOCAL
-bool memcached_binary_protocol_pedantic_check_response(protocol_binary_request_header *request,
- protocol_binary_response_header *response);
+bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
+ const protocol_binary_response_header *response);
LIBMEMCACHED_LOCAL
-enum MEMCACHED_PROTOCOL_EVENT memcached_binary_protocol_process_data(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+memcached_protocol_event_t memcached_binary_protocol_process_data(memcached_protocol_client_st *client, ssize_t *length, void **endptr);
#endif
* @param cas The CAS value to insert into the response (should be 0
* if you don't care)
*/
-typedef protocol_binary_response_status
+typedef protocol_binary_response_status
(*memcached_binary_protocol_get_response_handler)(const void *cookie,
const void *key,
uint16_t keylen,
uint64_t cas);
/**
* Callback to send data back from a STAT command
- *
+ *
* @param cookie Just pass along the cookie supplied in the callback
* @param key What to insert as key in the reply
* @param keylen The length of the key
* @param body What to store in the body of the package
* @param bodylen The number of bytes of the body
*/
-typedef protocol_binary_response_status
+typedef protocol_binary_response_status
(*memcached_binary_protocol_stat_response_handler)(const void *cookie,
const void *key,
uint16_t keylen,
uint32_t bodylen);
/**
* Callback to send data back from a VERSION command
- *
+ *
* @param cookie Just pass along the cookie supplied in the callback
* @param text The version string
* @param length The number of bytes in the version string
*/
-typedef protocol_binary_response_status
+typedef protocol_binary_response_status
(*memcached_binary_protocol_version_response_handler)(const void *cookie,
const void *text,
uint32_t length);
/**
* In the low level interface you need to format the response
- * packet yourself (giving you complete freedom :-)
+ * packet yourself (giving you complete freedom :-)
*
* @param cookie Just pass along the cookie supplied in the callback
* @param request Pointer to the request packet you are sending a reply to
/**
* In the low lever interface you have to do most of the work by
* yourself, but it also gives you a lot of freedom :-)
- * @param cookie identification for this connection, just pass it along to
+ * @param cookie identification for this connection, just pass it along to
* the response handler
* @param header the command received over the wire. Never try to access
* <u>anything</u> outside the command.
/**
* The raw interface to the packets is implemented in version 0. It contains
- * just an array with command handlers. The inxed in the array is the
+ * just an array with command handlers. The inxed in the array is the
* com code.
*/
-struct memcached_binary_protocol_callback_v0_st {
+typedef struct {
memcached_binary_protocol_command_handler comcode[256];
-};
+} memcached_binary_protocol_callback_v0_st;
+
/**
* The first version of the callback struct containing all of the
* documented commands in the initial release of the binary protocol
* (aka. memcached 1.4.0).
- *
+ *
* You might miss the Q commands (addq etc) but the response function
* knows how to deal with them so you don't need to worry about that :-)
*/
-struct memcached_binary_protocol_callback_v1_st {
+typedef struct {
/**
* Add an item to the cache
* @param cookie id of the client receiving the command
* @param exptime the expiry time for the key-value pair
* @param cas the resulting cas for the add operation (if success)
*/
- protocol_binary_response_status (*add)(const void *cookie,
- const void *key,
+ protocol_binary_response_status (*add)(const void *cookie,
+ const void *key,
uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
uint64_t *cas);
/**
* @param vallen the length of the data
* @param cas the CAS in the request
* @param result_cas the resulting cas for the append operation
- *
+ *
*/
- protocol_binary_response_status (*append)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
+ protocol_binary_response_status (*append)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
uint64_t cas,
uint64_t *result_cas);
* @param cas the CAS in the request
* @param result the result from the decrement
* @param result_cas the cas of the item
- *
+ *
*/
- protocol_binary_response_status (*decrement)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
+ protocol_binary_response_status (*decrement)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
uint32_t expiration,
uint64_t *result,
uint64_t *result_cas);
* @param len the length of the key
* @param cas the CAS in the request
*/
- protocol_binary_response_status (*delete)(const void *cookie,
- const void *key,
- uint16_t keylen,
+ protocol_binary_response_status (*delete)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
uint64_t cas);
* @param cookie id of the client receiving the command
* @param when when the cache should be flushed (0 == immediately)
*/
- protocol_binary_response_status (*flush)(const void *cookie,
+ protocol_binary_response_status (*flush)(const void *cookie,
uint32_t when);
* @param len the length of the key
* @param response_handler to send the result back to the client
*/
- protocol_binary_response_status (*get)(const void *cookie,
- const void *key,
- uint16_t keylen,
+ protocol_binary_response_status (*get)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
memcached_binary_protocol_get_response_handler response_handler);
/**
* @param cas the CAS in the request
* @param result the result from the decrement
* @param result_cas the cas of the item
- *
+ *
*/
- protocol_binary_response_status (*increment)(const void *cookie,
- const void *key,
- uint16_t keylen,
- uint64_t delta,
- uint64_t initial,
- uint32_t expiration,
+ protocol_binary_response_status (*increment)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ uint64_t delta,
+ uint64_t initial,
+ uint32_t expiration,
uint64_t *result,
uint64_t *result_cas);
/**
* The noop command was received. This is just a notification callback (the
* response is automatically created).
- *
+ *
* @param cookie id of the client receiving the command
*/
protocol_binary_response_status (*noop)(const void *cookie);
* @param vallen the length of the data
* @param cas the CAS in the request
* @param result-cas the cas id of the item
- *
+ *
*/
- protocol_binary_response_status (*prepend)(const void *cookie,
- const void *key,
- uint16_t keylen,
- const void* val,
- uint32_t vallen,
+ protocol_binary_response_status (*prepend)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
+ const void* val,
+ uint32_t vallen,
uint64_t cas,
uint64_t *result_cas);
/**
* The quit command was received. This is just a notification callback (the
* response is automatically created).
- *
+ *
* @param cookie id of the client receiving the command
*/
protocol_binary_response_status (*quit)(const void *cookie);
* @param cas the cas id in the request
* @param result_cas the cas id of the item
*/
- protocol_binary_response_status (*replace)(const void *cookie,
- const void *key,
+ protocol_binary_response_status (*replace)(const void *cookie,
+ const void *key,
uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
uint64_t cas,
uint64_t *result_cas);
* @param cas the cas id in the request
* @param result_cas the cas id of the new item
*/
- protocol_binary_response_status (*set)(const void *cookie,
- const void *key,
+ protocol_binary_response_status (*set)(const void *cookie,
+ const void *key,
uint16_t keylen,
- const void* val,
- uint32_t vallen,
- uint32_t flags,
- uint32_t exptime,
+ const void* val,
+ uint32_t vallen,
+ uint32_t flags,
+ uint32_t exptime,
uint64_t cas,
uint64_t *result_cas);
* @param keylen the length of the key
* @param response_handler to send the result back to the client, but
* don't send reply on success!
- *
+ *
*/
- protocol_binary_response_status (*stat)(const void *cookie,
- const void *key,
- uint16_t keylen,
+ protocol_binary_response_status (*stat)(const void *cookie,
+ const void *key,
+ uint16_t keylen,
memcached_binary_protocol_stat_response_handler response_handler);
/**
* @param cookie id of the client receiving the command
* @param response_handler to send the result back to the client, but
* don't send reply on success!
- *
+ *
*/
- protocol_binary_response_status (*version)(const void *cookie,
+ protocol_binary_response_status (*version)(const void *cookie,
memcached_binary_protocol_version_response_handler response_handler);
-};
+} memcached_binary_protocol_callback_v1_st;
/**
- *
+ *
*/
-struct memcached_binary_protocol_callback_st {
+typedef struct {
/**
* The interface version used (set to 0 if you don't have any specialized
* command handlers).
* at the content you <b>must</b> ensure that you don't
* try to access beyond the end of the message.
*/
- void (*pre_execute)(const void *cookie,
+ void (*pre_execute)(const void *cookie,
protocol_binary_request_header *header);
/**
* Callback fired just after the command was exected (please note
* passed as the pointer is valid as long as you use the protocol handler.
*/
union {
- struct memcached_binary_protocol_callback_v0_st v0;
+ memcached_binary_protocol_callback_v0_st v0;
/**
* The first version of the callback struct containing all of the
* documented commands in the initial release of the binary protocol
* (aka. memcached 1.4.0).
*/
- struct memcached_binary_protocol_callback_v1_st v1;
+ memcached_binary_protocol_callback_v1_st v1;
} interface;
-};
+} memcached_binary_protocol_callback_st;
#endif
* but some people still do). If it ever shows up as a performance thing
* I'll look into optimizing this ;-)
*/
-typedef bool (*drain_func)(struct memcached_protocol_client_st *client);
-typedef protocol_binary_response_status (*spool_func)(struct memcached_protocol_client_st *client,
+typedef bool (*drain_func)(memcached_protocol_client_st *client);
+typedef protocol_binary_response_status (*spool_func)(memcached_protocol_client_st *client,
const void *data,
size_t length);
* Definition of the per instance structure.
*/
struct memcached_protocol_st {
- struct memcached_binary_protocol_callback_st *callback;
+ memcached_binary_protocol_callback_st *callback;
memcached_protocol_recv_func recv;
memcached_protocol_send_func send;
#define CHUNK_BUFFERSIZE 2048
-typedef enum MEMCACHED_PROTOCOL_EVENT (*process_data)(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
+typedef memcached_protocol_event_t (*process_data)(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr);
enum ascii_cmd {
GET_CMD,
};
struct memcached_protocol_client_st {
- struct memcached_protocol_st *root;
+ memcached_protocol_st *root;
int sock;
int error;
#define ensure(a) if (!(a)) { return false; }
-bool memcached_binary_protocol_pedantic_check_request(protocol_binary_request_header *request)
+bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header *request)
{
ensure(request->request.magic == PROTOCOL_BINARY_REQ);
ensure(request->request.datatype == PROTOCOL_BINARY_RAW_BYTES);
return true;
}
-bool memcached_binary_protocol_pedantic_check_response(protocol_binary_request_header *request,
- protocol_binary_response_header *response)
+bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header *request,
+ const protocol_binary_response_header *response)
{
ensure(response->response.magic == PROTOCOL_BINARY_RES);
ensure(response->response.datatype == PROTOCOL_BINARY_RAW_BYTES);
return NULL;
}
- ret->offset = ret->nbytes = 0;
- ret->next = NULL;
- ret->size = CHUNK_BUFFERSIZE;
+ ret->offset= ret->nbytes= 0;
+ ret->next= NULL;
+ ret->size= CHUNK_BUFFERSIZE;
ret->data= (void*)(ret + 1);
if (client->output == NULL)
{
- client->output = client->output_tail = ret;
+ client->output= client->output_tail= ret;
}
else
{
return PROTOCOL_BINARY_RESPONSE_SUCCESS;
}
- size_t offset = 0;
+ size_t offset= 0;
struct chunk_st *chunk= client->output;
while (offset < length)
}
}
- size_t bulk = length - offset;
+ size_t bulk= length - offset;
if (bulk > chunk->size - chunk->nbytes)
{
- bulk = chunk->size - chunk->nbytes;
+ bulk= chunk->size - chunk->nbytes;
}
memcpy(chunk->data + chunk->nbytes, data, bulk);
* so the implementors needs to provide an implementation of that interface
*
*/
-static enum MEMCACHED_PROTOCOL_EVENT determine_protocol(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
+static memcached_protocol_event_t determine_protocol(struct memcached_protocol_client_st *client, ssize_t *length, void **endptr)
{
if (*client->root->input_buffer == (uint8_t)PROTOCOL_BINARY_REQ)
{
const char *err= "CLIENT_ERROR: Unsupported protocol\r\n";
client->root->spool(client, err, strlen(err));
client->root->drain(client);
- return ERROR_EVENT; /* Unsupported protocol */
+ return MEMCACHED_PROTOCOL_ERROR_EVENT; /* Unsupported protocol */
}
return client->work(client, length, endptr);
return NULL;
}
- ret->buffer_cache = cache_create("protocol_handler",
+ ret->buffer_cache= cache_create("protocol_handler",
CHUNK_BUFFERSIZE + sizeof(struct chunk_st),
0, NULL, NULL);
- if (ret->buffer_cache == NULL)
+ if (ret->buffer_cache == NULL)
{
free(ret->input_buffer);
free(ret);
free(client);
}
-enum MEMCACHED_PROTOCOL_EVENT memcached_protocol_client_work(struct memcached_protocol_client_st *client)
+memcached_protocol_event_t memcached_protocol_client_work(struct memcached_protocol_client_st *client)
{
/* Try to send data and read from the socket */
bool more_data= true;
}
void *endptr;
- if (client->work(client, &len, &endptr) == ERROR_EVENT)
+ memcached_protocol_event_t events= client->work(client, &len, &endptr);
+ if (events == MEMCACHED_PROTOCOL_ERROR_EVENT)
{
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
if (len > 0)
if (client->input_buffer == NULL)
{
client->error= ENOMEM;
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
memcpy(client->input_buffer, endptr, (size_t)len);
client->input_buffer_offset= (size_t)len;
{
/* Connection closed */
drain_output(client);
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
else
{
{
client->error= errno;
/* mark this client as terminated! */
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
- more_data = false;
+ more_data= false;
}
} while (more_data);
if (!drain_output(client))
{
- return ERROR_EVENT;
+ return MEMCACHED_PROTOCOL_ERROR_EVENT;
}
- return (client->output) ? READ_WRITE_EVENT : READ_EVENT;
+ memcached_protocol_event_t ret= MEMCACHED_PROTOCOL_READ_EVENT;
+ if (client->output)
+ ret|= MEMCACHED_PROTOCOL_READ_EVENT;
+
+ return ret;
}
* and never assume anything about the internal layout / sizes of the
* structures.
*/
-struct memcached_protocol_st;
-struct memcached_protocol_client_st;
+typedef struct memcached_protocol_st memcached_protocol_st;
+typedef struct memcached_protocol_client_st memcached_protocol_client_st;
/**
* Function the protocol handler should call to receive data.
*/
typedef ssize_t (*memcached_protocol_recv_func)(const void *cookie,
int fd,
- void *buf,
+ void *buf,
size_t nbuf);
/**
*/
typedef ssize_t (*memcached_protocol_send_func)(const void *cookie,
int fd,
- const void *buf,
+ const void *buf,
size_t nbuf);
/**
* @return NULL if allocation of an instance fails
*/
LIBMEMCACHED_API
-struct memcached_protocol_st *memcached_protocol_create_instance(void);
+memcached_protocol_st *memcached_protocol_create_instance(void);
/**
* Get the callbacks associated with a protocol handler instance
* @return the callbacks currently used
*/
LIBMEMCACHED_API
-struct memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(struct memcached_protocol_st *instance);
+memcached_binary_protocol_callback_st *memcached_binary_protocol_get_callbacks(memcached_protocol_st *instance);
/**
* Set the callbacks to be used by the given protocol handler instance
* @param callback the callbacks to use
*/
LIBMEMCACHED_API
-void memcached_binary_protocol_set_callbacks(struct memcached_protocol_st *instance, struct memcached_binary_protocol_callback_st *callback);
+void memcached_binary_protocol_set_callbacks(memcached_protocol_st *instance, memcached_binary_protocol_callback_st *callback);
/**
* Should the library inspect the packages being sent and received and verify
* @param enable true if you want the library to check packages, false otherwise
*/
LIBMEMCACHED_API
-void memcached_binary_protocol_set_pedantic(struct memcached_protocol_st *instance, bool enable);
+void memcached_binary_protocol_set_pedantic(memcached_protocol_st *instance, bool enable);
/**
* Is the library inpecting each package?
* @return true it the library is inspecting each package, false otherwise
*/
LIBMEMCACHED_API
-bool memcached_binary_protocol_get_pedantic(struct memcached_protocol_st *instance);
+bool memcached_binary_protocol_get_pedantic(memcached_protocol_st *instance);
/**
* Destroy an instance of the protocol handler
* @param instance The instance to destroy
*/
LIBMEMCACHED_API
-void memcached_protocol_destroy_instance(struct memcached_protocol_st *instance);
+void memcached_protocol_destroy_instance(memcached_protocol_st *instance);
/**
* Set the IO functions used by the instance to send and receive data. The
- * functions should behave like recv(3socket) and send(3socket).
- *
+ * functions should behave like recv(3socket) and send(3socket).
+ *
* @param instance the instance to specify the IO functions for
* @param recv the function to call for reciving data
* @param send the function to call for sending data
*/
LIBMEMCACHED_API
-void memached_protocol_set_io_functions(struct memcached_protocol_st *instance,
- memcached_protocol_recv_func recv,
+void memached_protocol_set_io_functions(memcached_protocol_st *instance,
+ memcached_protocol_recv_func recv,
memcached_protocol_send_func send);
* Create a new client instance and associate it with a socket
* @param instance the protocol instance to bind the client to
* @param sock the client socket
- * @return NULL if allocation fails, otherwise an instance
+ * @return NULL if allocation fails, otherwise an instance
*/
LIBMEMCACHED_API
-struct memcached_protocol_client_st *memcached_protocol_create_client(struct memcached_protocol_st *instance, int sock);
+memcached_protocol_client_st *memcached_protocol_create_client(memcached_protocol_st *instance, int sock);
/**
* Destroy a client handle.
- * The caller needs to close the socket accociated with the client
+ * The caller needs to close the socket accociated with the client
* <b>before</b> calling this function. This function invalidates the
* client memory area.
*
* @param client the client to destroy
*/
LIBMEMCACHED_API
-void memcached_protocol_client_destroy(struct memcached_protocol_client_st *client);
+void memcached_protocol_client_destroy(memcached_protocol_client_st *client);
+
+/**
+ * Error event means that the client encountered an error with the
+ * connection so you should shut it down
+ */
+#define MEMCACHED_PROTOCOL_ERROR_EVENT 1
+/**
+ * Please notify when there is more data available to read
+ */
+#define MEMCACHED_PROTOCOL_READ_EVENT 2
+/**
+ * Please notify when it is possible to send more data
+ */
+#define MEMCACHED_PROTOCOL_WRITE_EVENT 4
+/**
+ * Backed paused the execution for this client
+ */
+#define MEMCACHED_PROTOCOL_PAUSE_EVENT 8
/**
- * The different events the client is interested in
+ * The different events the client is interested in. This is a bitmask of
+ * the constants defined above.
*/
-enum MEMCACHED_PROTOCOL_EVENT {
- /* Error event means that the client encountered an error with the
- * connection so you should shut it down */
- ERROR_EVENT,
- /* Please notify when there is more data available to read */
- READ_EVENT,
- /* Please notify when it is possible to send more data */
- WRITE_EVENT,
- /* Please notify when it is possible to send or receive data */
- READ_WRITE_EVENT
-};
+typedef uint32_t memcached_protocol_event_t;
/**
- * Let the client do some work. This might involve reading / sending data
+ * Let the client do some work. This might involve reading / sending data
* to/from the client, or perform callbacks to execute a command.
* @param client the client structure to work on
* @return The next event the protocol handler will be notified for
*/
LIBMEMCACHED_API
-enum MEMCACHED_PROTOCOL_EVENT memcached_protocol_client_work(struct memcached_protocol_client_st *client);
+memcached_protocol_event_t memcached_protocol_client_work(memcached_protocol_client_st *client);
/**
* Get the socket attached to a client handle
* @return the socket handle
*/
LIBMEMCACHED_API
-int memcached_protocol_client_get_socket(struct memcached_protocol_client_st *client);
+int memcached_protocol_client_get_socket(memcached_protocol_client_st *client);
/**
* Get the error id socket attached to a client handle
* @return the OS error code from the client
*/
LIBMEMCACHED_API
-int memcached_protocol_client_get_errno(struct memcached_protocol_client_st *client);
+int memcached_protocol_client_get_errno(memcached_protocol_client_st *client);
/**
* Get a raw response handler for the given cookie