No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / util / netstring.c
blobfec74f77cbbfe765b06636ead285911e2657db70
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* netstring 3
6 /* SUMMARY
7 /* netstring stream I/O support
8 /* SYNOPSIS
9 /* #include <netstring.h>
11 /* void netstring_setup(stream, timeout)
12 /* VSTREAM *stream;
13 /* int timeout;
15 /* void netstring_except(stream, exception)
16 /* VSTREAM *stream;
17 /* int exception;
19 /* VSTRING *netstring_get(stream, buf, limit)
20 /* VSTREAM *stream;
21 /* VSTRING *buf;
22 /* ssize_t limit;
24 /* void netstring_put(stream, data, len)
25 /* VSTREAM *stream;
26 /* const char *data;
27 /* ssize_t len;
29 /* void netstring_put_multi(stream, data, len, data, len, ..., 0)
30 /* VSTREAM *stream;
31 /* const char *data;
32 /* ssize_t len;
34 /* void NETSTRING_PUT_BUF(stream, buf)
35 /* VSTREAM *stream;
36 /* VSTRING *buf;
38 /* void netstring_fflush(stream)
39 /* VSTREAM *stream;
41 /* VSTRING *netstring_memcpy(buf, data, len)
42 /* VSTRING *buf;
43 /* const char *data;
44 /* ssize_t len;
46 /* VSTRING *netstring_memcat(buf, data, len)
47 /* VSTRING *buf;
48 /* const char *src;
49 /* ssize_t len;
50 /* AUXILIARY ROUTINES
51 /* ssize_t netstring_get_length(stream)
52 /* VSTREAM *stream;
54 /* VSTRING *netstring_get_data(stream, buf, len)
55 /* VSTREAM *stream;
56 /* VSTRING *buf;
57 /* ssize_t len;
59 /* void netstring_get_terminator(stream)
60 /* VSTREAM *stream;
61 /* DESCRIPTION
62 /* This module reads and writes netstrings with error detection:
63 /* timeouts, unexpected end-of-file, or format errors. Netstring
64 /* is a data format designed by Daniel Bernstein.
66 /* netstring_setup() arranges for a time limit on the netstring
67 /* read and write operations described below.
68 /* This routine alters the behavior of streams as follows:
69 /* .IP \(bu
70 /* The read/write timeout is set to the specified value.
71 /* .IP \(bu
72 /* The stream is configured to enable exception handling.
73 /* .PP
74 /* netstring_except() raises the specified exception on the
75 /* named stream. See the DIAGNOSTICS section below.
77 /* netstring_get() reads a netstring from the specified stream
78 /* and extracts its content. The limit specifies a maximal size.
79 /* Specify zero to disable the size limit. The result is not null
80 /* terminated. The result value is the buf argument.
82 /* netstring_put() encapsulates the specified string as a netstring
83 /* and sends the result to the specified stream.
84 /* The stream output buffer is not flushed.
86 /* netstring_put_multi() encapsulates the content of multiple strings
87 /* as one netstring and sends the result to the specified stream. The
88 /* argument list must be terminated with a null data pointer.
89 /* The stream output buffer is not flushed.
91 /* NETSTRING_PUT_BUF() is a macro that provides a VSTRING-based
92 /* wrapper for the netstring_put() routine.
94 /* netstring_fflush() flushes the output buffer of the specified
95 /* stream and handles any errors.
97 /* netstring_memcpy() encapsulates the specified data as a netstring
98 /* and copies the result over the specified buffer. The result
99 /* value is the buffer.
101 /* netstring_memcat() encapsulates the specified data as a netstring
102 /* and appends the result to the specified buffer. The result
103 /* value is the buffer.
105 /* The following routines provide low-level access to a netstring
106 /* stream.
108 /* netstring_get_length() reads a length field from the specified
109 /* stream, and absorbs the netstring length field terminator.
111 /* netstring_get_data() reads the specified number of bytes from the
112 /* specified stream into the specified buffer, and absorbs the
113 /* netstring terminator. The result value is the buf argument.
115 /* netstring_get_terminator() reads the netstring terminator from
116 /* the specified stream.
117 /* DIAGNOSTICS
118 /* .fi
119 /* .ad
120 /* In case of error, a vstream_longjmp() call is performed to the
121 /* context specified with vstream_setjmp().
122 /* Error codes passed along with vstream_longjmp() are:
123 /* .IP NETSTRING_ERR_EOF
124 /* An I/O error happened, or the peer has disconnected unexpectedly.
125 /* .IP NETSTRING_ERR_TIME
126 /* The time limit specified to netstring_setup() was exceeded.
127 /* .IP NETSTRING_ERR_FORMAT
128 /* The input contains an unexpected character value.
129 /* .IP NETSTRING_ERR_SIZE
130 /* The input is larger than acceptable.
131 /* BUGS
132 /* The timeout deadline affects all I/O on the named stream, not
133 /* just the I/O done on behalf of this module.
135 /* The timeout deadline overwrites any previously set up state on
136 /* the named stream.
138 /* netstrings are not null terminated, which makes printing them
139 /* a bit awkward.
140 /* LICENSE
141 /* .ad
142 /* .fi
143 /* The Secure Mailer license must be distributed with this software.
144 /* SEE ALSO
145 /* http://cr.yp.to/proto/netstrings.txt, netstring definition
146 /* AUTHOR(S)
147 /* Wietse Venema
148 /* IBM T.J. Watson Research
149 /* P.O. Box 704
150 /* Yorktown Heights, NY 10598, USA
151 /*--*/
153 /* System library. */
155 #include <sys_defs.h>
156 #include <stdarg.h>
157 #include <ctype.h>
159 /* Utility library. */
161 #include <msg.h>
162 #include <vstream.h>
163 #include <vstring.h>
164 #include <netstring.h>
166 /* Application-specific. */
168 #define STR(x) vstring_str(x)
169 #define LEN(x) VSTRING_LEN(x)
171 /* netstring_setup - initialize netstring stream */
173 void netstring_setup(VSTREAM *stream, int timeout)
175 vstream_control(stream,
176 VSTREAM_CTL_TIMEOUT, timeout,
177 VSTREAM_CTL_EXCEPT,
178 VSTREAM_CTL_END);
181 /* netstring_except - process netstring stream exception */
183 void netstring_except(VSTREAM *stream, int exception)
185 vstream_longjmp(stream, exception);
188 /* netstring_get_length - read netstring length + terminator */
190 ssize_t netstring_get_length(VSTREAM *stream)
192 const char *myname = "netstring_get_length";
193 ssize_t len = 0;
194 int ch;
196 for (;;) {
197 switch (ch = VSTREAM_GETC(stream)) {
198 case VSTREAM_EOF:
199 netstring_except(stream, vstream_ftimeout(stream) ?
200 NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
201 case ':':
202 if (msg_verbose > 1)
203 msg_info("%s: read netstring length %ld", myname, (long) len);
204 return (len);
205 default:
206 if (!ISDIGIT(ch))
207 netstring_except(stream, NETSTRING_ERR_FORMAT);
208 len = len * 10 + ch - '0';
209 /* vstream_fread() would read zero bytes. Reject input anyway. */
210 if (len < 0)
211 netstring_except(stream, NETSTRING_ERR_SIZE);
212 break;
217 /* netstring_get_data - read netstring payload + terminator */
219 VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, ssize_t len)
221 const char *myname = "netstring_get_data";
224 * Allocate buffer space.
226 VSTRING_RESET(buf);
227 VSTRING_SPACE(buf, len);
230 * Read the payload and absorb the terminator.
232 if (vstream_fread(stream, STR(buf), len) != len)
233 netstring_except(stream, vstream_ftimeout(stream) ?
234 NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
235 if (msg_verbose > 1)
236 msg_info("%s: read netstring data %.*s",
237 myname, (int) (len < 30 ? len : 30), STR(buf));
238 netstring_get_terminator(stream);
241 * Position the buffer.
243 VSTRING_AT_OFFSET(buf, len);
244 return (buf);
247 /* netstring_get_terminator - absorb netstring terminator */
249 void netstring_get_terminator(VSTREAM *stream)
251 if (VSTREAM_GETC(stream) != ',')
252 netstring_except(stream, NETSTRING_ERR_FORMAT);
255 /* netstring_get - read string from netstring stream */
257 VSTRING *netstring_get(VSTREAM *stream, VSTRING *buf, ssize_t limit)
259 ssize_t len;
261 len = netstring_get_length(stream);
262 if (limit && len > limit)
263 netstring_except(stream, NETSTRING_ERR_SIZE);
264 netstring_get_data(stream, buf, len);
265 return (buf);
268 /* netstring_put - send string as netstring */
270 void netstring_put(VSTREAM *stream, const char *data, ssize_t len)
272 const char *myname = "netstring_put";
274 if (msg_verbose > 1)
275 msg_info("%s: write netstring len %ld data %.*s",
276 myname, (long) len, (int) (len < 30 ? len : 30), data);
277 vstream_fprintf(stream, "%ld:", (long) len);
278 vstream_fwrite(stream, data, len);
279 VSTREAM_PUTC(',', stream);
282 /* netstring_put_multi - send multiple strings as one netstring */
284 void netstring_put_multi(VSTREAM *stream,...)
286 const char *myname = "netstring_put_multi";
287 ssize_t total;
288 char *data;
289 ssize_t data_len;
290 va_list ap;
293 * Figure out the total result size.
295 va_start(ap, stream);
296 for (total = 0; (data = va_arg(ap, char *)) != 0; total += data_len)
297 if ((data_len = va_arg(ap, ssize_t)) < 0)
298 msg_panic("netstring_put_multi: bad data length %ld", (long) data_len);
299 va_end(ap);
302 * Debugging support.
304 if (msg_verbose > 1) {
305 va_start(ap, stream);
306 data = va_arg(ap, char *);
307 data_len = va_arg(ap, ssize_t);
308 msg_info("%s: write netstring len %ld data %.*s",
309 myname, (long) total, (int) (data_len < 30 ? data_len : 30), data);
310 va_end(ap);
314 * Send the length, content and terminator.
316 vstream_fprintf(stream, "%ld:", (long) total);
317 va_start(ap, stream);
318 while ((data = va_arg(ap, char *)) != 0) {
319 data_len = va_arg(ap, ssize_t);
320 if (data_len > 0)
321 if (vstream_fwrite(stream, data, data_len) != data_len)
322 netstring_except(stream, vstream_ftimeout(stream) ?
323 NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
325 va_end(ap);
326 vstream_fwrite(stream, ",", 1);
329 /* netstring_fflush - flush netstring stream */
331 void netstring_fflush(VSTREAM *stream)
333 if (vstream_fflush(stream) == VSTREAM_EOF)
334 netstring_except(stream, vstream_ftimeout(stream) ?
335 NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
338 /* netstring_memcpy - copy data as in-memory netstring */
340 VSTRING *netstring_memcpy(VSTRING *buf, const char *src, ssize_t len)
342 vstring_sprintf(buf, "%ld:", (long) len);
343 vstring_memcat(buf, src, len);
344 VSTRING_ADDCH(buf, ',');
345 return (buf);
348 /* netstring_memcat - append data as in-memory netstring */
350 VSTRING *netstring_memcat(VSTRING *buf, const char *src, ssize_t len)
352 vstring_sprintf_append(buf, "%ld:", (long) len);
353 vstring_memcat(buf, src, len);
354 VSTRING_ADDCH(buf, ',');
355 return (buf);