xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/memcache_proto.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
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