1 /* $NetBSD: memcache_proto.c,v 1.1.1.2 2014/07/06 19:27:51 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 #include <compat_va_copy.h> 55 56 /* Application-specific. */ 57 58 #include <memcache_proto.h> 59 60 #define STR(x) vstring_str(x) 61 #define LEN(x) VSTRING_LEN(x) 62 63 /* memcache_get - read one line from peer */ 64 65 int memcache_get(VSTREAM *stream, VSTRING *vp, ssize_t bound) 66 { 67 int last_char; 68 int next_char; 69 70 last_char = (bound == 0 ? vstring_get(vp, stream) : 71 vstring_get_bound(vp, stream, bound)); 72 73 switch (last_char) { 74 75 /* 76 * Do some repair in the rare case that we stopped reading in the 77 * middle of the CRLF record terminator. 78 */ 79 case '\r': 80 if ((next_char = VSTREAM_GETC(stream)) == '\n') { 81 VSTRING_ADDCH(vp, '\n'); 82 /* FALLTRHOUGH */ 83 } else { 84 if (next_char != VSTREAM_EOF) 85 vstream_ungetc(stream, next_char); 86 87 /* 88 * Input too long, or EOF 89 */ 90 default: 91 if (msg_verbose) 92 msg_info("%s got %s", VSTREAM_PATH(stream), 93 LEN(vp) < bound ? "EOF" : "input too long"); 94 return (-1); 95 } 96 97 /* 98 * Strip off the record terminator: either CRLF or just bare LF. 99 */ 100 case '\n': 101 vstring_truncate(vp, VSTRING_LEN(vp) - 1); 102 if (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') 103 vstring_truncate(vp, VSTRING_LEN(vp) - 1); 104 VSTRING_TERMINATE(vp); 105 if (msg_verbose) 106 msg_info("%s got: %s", VSTREAM_PATH(stream), STR(vp)); 107 return (0); 108 } 109 } 110 111 /* memcache_fwrite - write one blob to peer */ 112 113 int memcache_fwrite(VSTREAM *stream, const char *cp, ssize_t todo) 114 { 115 116 /* 117 * Sanity check. 118 */ 119 if (todo < 0) 120 msg_panic("memcache_fwrite: negative todo %ld", (long) todo); 121 122 /* 123 * Do the I/O. 124 */ 125 if (msg_verbose) 126 msg_info("%s write: %.*s", VSTREAM_PATH(stream), (int) todo, cp); 127 if (vstream_fwrite(stream, cp, todo) != todo 128 || vstream_fputs("\r\n", stream) == VSTREAM_EOF) 129 return (-1); 130 else 131 return (0); 132 } 133 134 /* memcache_fread - read one blob from peer */ 135 136 int memcache_fread(VSTREAM *stream, VSTRING *buf, ssize_t todo) 137 { 138 139 /* 140 * Sanity check. 141 */ 142 if (todo < 0) 143 msg_panic("memcache_fread: negative todo %ld", (long) todo); 144 145 /* 146 * Do the I/O. 147 */ 148 VSTRING_SPACE(buf, todo); 149 VSTRING_AT_OFFSET(buf, todo); 150 if (vstream_fread(stream, STR(buf), todo) != todo 151 || VSTREAM_GETC(stream) != '\r' 152 || VSTREAM_GETC(stream) != '\n') { 153 if (msg_verbose) 154 msg_info("%s read: error", VSTREAM_PATH(stream)); 155 return (-1); 156 } else { 157 vstring_truncate(buf, todo); 158 VSTRING_TERMINATE(buf); 159 if (msg_verbose) 160 msg_info("%s read: %s", VSTREAM_PATH(stream), STR(buf)); 161 return (0); 162 } 163 } 164 165 /* memcache_vprintf - write one line to peer */ 166 167 int memcache_vprintf(VSTREAM *stream, const char *fmt, va_list ap) 168 { 169 170 /* 171 * Do the I/O. 172 */ 173 vstream_vfprintf(stream, fmt, ap); 174 vstream_fputs("\r\n", stream); 175 if (vstream_ferror(stream)) 176 return (-1); 177 else 178 return (0); 179 } 180 181 /* memcache_printf - write one line to peer */ 182 183 int memcache_printf(VSTREAM *stream, const char *fmt,...) 184 { 185 va_list ap; 186 int ret; 187 188 va_start(ap, fmt); 189 190 if (msg_verbose) { 191 VSTRING *buf = vstring_alloc(100); 192 va_list ap2; 193 194 VA_COPY(ap2, ap); 195 vstring_vsprintf(buf, fmt, ap2); 196 va_end(ap2); 197 msg_info("%s write: %s", VSTREAM_PATH(stream), STR(buf)); 198 vstring_free(buf); 199 } 200 201 /* 202 * Do the I/O. 203 */ 204 ret = memcache_vprintf(stream, fmt, ap); 205 va_end(ap); 206 return (ret); 207 } 208