1 /* $NetBSD: memcache_proto.c,v 1.1.1.1 2013/01/02 18:58:59 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* memcache_proto 3 6 /* SUMMARY 7 /* memcache low-level protocol 8 /* SYNOPSIS 9 /* #include <memcache_proto.h> 10 /* 11 /* int memcache_get(fp, buf, len) 12 /* VSTREAM *fp; 13 /* VSTRING *buf; 14 /* ssize_t len; 15 /* 16 /* int memcache_printf(fp, format, ...) 17 /* VSTREAM *fp; 18 /* const char *format; 19 /* 20 /* int memcache_vprintf(fp, format, ap) 21 /* VSTREAM *fp; 22 /* const char *format; 23 /* va_list ap; 24 /* 25 /* int memcache_fread(fp, buf, len) 26 /* VSTREAM *fp; 27 /* VSTRING *buf; 28 /* ssize_t len; 29 /* 30 /* int memcache_fwrite(fp, buf, len) 31 /* VSTREAM *fp; 32 /* const char *buf; 33 /* ssize_t len; 34 /* DESCRIPTION 35 /* This module implements the low-level memcache protocol. 36 /* All functions return -1 on error and 0 on succcess. 37 /* SEE ALSO 38 /* smtp_proto(3) SMTP low-level protocol. 39 /* AUTHOR(S) 40 /* Wietse Venema 41 /* IBM T.J. Watson Research 42 /* P.O. Box 704 43 /* Yorktown Heights, NY 10598, USA 44 /*--*/ 45 46 #include <sys_defs.h> 47 48 /* Utility library. */ 49 50 #include <msg.h> 51 #include <vstream.h> 52 #include <vstring.h> 53 #include <vstring_vstream.h> 54 55 /* Application-specific. */ 56 57 #include <memcache_proto.h> 58 59 #define STR(x) vstring_str(x) 60 #define LEN(x) VSTRING_LEN(x) 61 62 /* memcache_get - read one line from peer */ 63 64 int memcache_get(VSTREAM *stream, VSTRING *vp, ssize_t bound) 65 { 66 int last_char; 67 int next_char; 68 69 last_char = (bound == 0 ? vstring_get(vp, stream) : 70 vstring_get_bound(vp, stream, bound)); 71 72 switch (last_char) { 73 74 /* 75 * Do some repair in the rare case that we stopped reading in the 76 * middle of the CRLF record terminator. 77 */ 78 case '\r': 79 if ((next_char = VSTREAM_GETC(stream)) == '\n') { 80 VSTRING_ADDCH(vp, '\n'); 81 /* FALLTRHOUGH */ 82 } else { 83 if (next_char != VSTREAM_EOF) 84 vstream_ungetc(stream, next_char); 85 86 /* 87 * Input too long, or EOF 88 */ 89 default: 90 if (msg_verbose) 91 msg_info("%s got %s", VSTREAM_PATH(stream), 92 LEN(vp) < bound ? "EOF" : "input too long"); 93 return (-1); 94 } 95 96 /* 97 * Strip off the record terminator: either CRLF or just bare LF. 98 */ 99 case '\n': 100 vstring_truncate(vp, VSTRING_LEN(vp) - 1); 101 if (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') 102 vstring_truncate(vp, VSTRING_LEN(vp) - 1); 103 VSTRING_TERMINATE(vp); 104 if (msg_verbose) 105 msg_info("%s got: %s", VSTREAM_PATH(stream), STR(vp)); 106 return (0); 107 } 108 } 109 110 /* memcache_fwrite - write one blob to peer */ 111 112 int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo) 113 { 114 115 /* 116 * Sanity check. 117 */ 118 if (todo < 0) 119 msg_panic("memcache_fwrite: negative todo %ld", (long) todo); 120 121 /* 122 * Do the I/O. 123 */ 124 if (msg_verbose) 125 msg_info("%s write: %.*s", VSTREAM_PATH(stream), (int) todo, cp); 126 if (vstream_fwrite(stream, cp, todo) != todo 127 || vstream_fputs("\r\n", stream) == VSTREAM_EOF) 128 return (-1); 129 else 130 return (0); 131 } 132 133 /* memcache_fread - read one blob from peer */ 134 135 int memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo) 136 { 137 138 /* 139 * Sanity check. 140 */ 141 if (todo < 0) 142 msg_panic("memcache_fread: negative todo %ld", (long) todo); 143 144 /* 145 * Do the I/O. 146 */ 147 VSTRING_SPACE(buf, todo); 148 VSTRING_AT_OFFSET(buf, todo); 149 if (vstream_fread(stream, STR(buf), todo) != todo 150 || VSTREAM_GETC(stream) != '\r' 151 || VSTREAM_GETC(stream) != '\n') { 152 if (msg_verbose) 153 msg_info("%s read: error", VSTREAM_PATH(stream)); 154 return (-1); 155 } else { 156 vstring_truncate(buf, todo); 157 VSTRING_TERMINATE(buf); 158 if (msg_verbose) 159 msg_info("%s read: %s", VSTREAM_PATH(stream), STR(buf)); 160 return (0); 161 } 162 } 163 164 /* memcache_vprintf - write one line to peer */ 165 166 int memcache_vprintf(VSTREAM *stream, const char *fmt, va_list ap) 167 { 168 169 /* 170 * Do the I/O. 171 */ 172 vstream_vfprintf(stream, fmt, ap); 173 vstream_fputs("\r\n", stream); 174 if (vstream_ferror(stream)) 175 return (-1); 176 else 177 return (0); 178 } 179 180 /* memcache_printf - write one line to peer */ 181 182 int memcache_printf(VSTREAM *stream, const char *fmt,...) 183 { 184 va_list ap; 185 int ret; 186 187 if (msg_verbose) { 188 VSTRING *buf = vstring_alloc(100); 189 190 va_start(ap, fmt); 191 vstring_vsprintf(buf, fmt, ap); 192 va_end(ap); 193 msg_info("%s write: %s", VSTREAM_PATH(stream), STR(buf)); 194 vstring_free(buf); 195 } 196 197 /* 198 * Do the I/O. 199 */ 200 va_start(ap, fmt); 201 ret = memcache_vprintf(stream, fmt, ap); 202 va_end(ap); 203 return (ret); 204 } 205