diff options
Diffstat (limited to 'src/global/memcache_proto.c')
-rw-r--r-- | src/global/memcache_proto.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/src/global/memcache_proto.c b/src/global/memcache_proto.c new file mode 100644 index 0000000..58a7e3c --- /dev/null +++ b/src/global/memcache_proto.c @@ -0,0 +1,207 @@ +/*++ +/* NAME +/* memcache_proto 3 +/* SUMMARY +/* memcache low-level protocol +/* SYNOPSIS +/* #include <memcache_proto.h> +/* +/* int memcache_get(fp, buf, len) +/* VSTREAM *fp; +/* VSTRING *buf; +/* ssize_t len; +/* +/* int memcache_printf(fp, format, ...) +/* VSTREAM *fp; +/* const char *format; +/* +/* int memcache_vprintf(fp, format, ap) +/* VSTREAM *fp; +/* const char *format; +/* va_list ap; +/* +/* int memcache_fread(fp, buf, len) +/* VSTREAM *fp; +/* VSTRING *buf; +/* ssize_t len; +/* +/* int memcache_fwrite(fp, buf, len) +/* VSTREAM *fp; +/* const char *buf; +/* ssize_t len; +/* DESCRIPTION +/* This module implements the low-level memcache protocol. +/* All functions return -1 on error and 0 on succcess. +/* SEE ALSO +/* smtp_proto(3) SMTP low-level protocol. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + +#include <sys_defs.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstream.h> +#include <vstring.h> +#include <vstring_vstream.h> +#include <compat_va_copy.h> + +/* Application-specific. */ + +#include <memcache_proto.h> + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* memcache_get - read one line from peer */ + +int memcache_get(VSTREAM *stream, VSTRING *vp, ssize_t bound) +{ + int last_char; + int next_char; + + last_char = (bound == 0 ? vstring_get(vp, stream) : + vstring_get_bound(vp, stream, bound)); + + switch (last_char) { + + /* + * Do some repair in the rare case that we stopped reading in the + * middle of the CRLF record terminator. + */ + case '\r': + if ((next_char = VSTREAM_GETC(stream)) == '\n') { + VSTRING_ADDCH(vp, '\n'); + /* FALLTRHOUGH */ + } else { + if (next_char != VSTREAM_EOF) + vstream_ungetc(stream, next_char); + + /* + * Input too long, or EOF + */ + default: + if (msg_verbose) + msg_info("%s got %s", VSTREAM_PATH(stream), + LEN(vp) < bound ? "EOF" : "input too long"); + return (-1); + } + + /* + * Strip off the record terminator: either CRLF or just bare LF. + */ + case '\n': + vstring_truncate(vp, VSTRING_LEN(vp) - 1); + if (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') + vstring_truncate(vp, VSTRING_LEN(vp) - 1); + VSTRING_TERMINATE(vp); + if (msg_verbose) + msg_info("%s got: %s", VSTREAM_PATH(stream), STR(vp)); + return (0); + } +} + +/* memcache_fwrite - write one blob to peer */ + +int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo) +{ + + /* + * Sanity check. + */ + if (todo < 0) + msg_panic("memcache_fwrite: negative todo %ld", (long) todo); + + /* + * Do the I/O. + */ + if (msg_verbose) + msg_info("%s write: %.*s", VSTREAM_PATH(stream), (int) todo, cp); + if (vstream_fwrite(stream, cp, todo) != todo + || vstream_fputs("\r\n", stream) == VSTREAM_EOF) + return (-1); + else + return (0); +} + +/* memcache_fread - read one blob from peer */ + +int memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo) +{ + + /* + * Sanity check. + */ + if (todo < 0) + msg_panic("memcache_fread: negative todo %ld", (long) todo); + + /* + * Do the I/O. + */ + if (vstream_fread_buf(stream, buf, todo) != todo + || VSTREAM_GETC(stream) != '\r' + || VSTREAM_GETC(stream) != '\n') { + if (msg_verbose) + msg_info("%s read: error", VSTREAM_PATH(stream)); + return (-1); + } else { + VSTRING_TERMINATE(buf); + if (msg_verbose) + msg_info("%s read: %s", VSTREAM_PATH(stream), STR(buf)); + return (0); + } +} + +/* memcache_vprintf - write one line to peer */ + +int memcache_vprintf(VSTREAM *stream, const char *fmt, va_list ap) +{ + + /* + * Do the I/O. + */ + vstream_vfprintf(stream, fmt, ap); + vstream_fputs("\r\n", stream); + if (vstream_ferror(stream)) + return (-1); + else + return (0); +} + +/* memcache_printf - write one line to peer */ + +int memcache_printf(VSTREAM *stream, const char *fmt,...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + + if (msg_verbose) { + VSTRING *buf = vstring_alloc(100); + va_list ap2; + + VA_COPY(ap2, ap); + vstring_vsprintf(buf, fmt, ap2); + va_end(ap2); + msg_info("%s write: %s", VSTREAM_PATH(stream), STR(buf)); + vstring_free(buf); + } + + /* + * Do the I/O. + */ + ret = memcache_vprintf(stream, fmt, ap); + va_end(ap); + return (ret); +} |