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