#include <stdarg.h>
[libpwmd.git] / assuan / assuan-buffer.c
blob39685842d95275748f6fc14256942eaeda8341de
1 /* assuan-buffer.c - read and send data
2 * Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
4 * This file is part of Assuan.
6 * Assuan is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * Assuan is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <assert.h>
27 #ifdef HAVE_W32_SYSTEM
28 #include <process.h>
29 #endif
30 #include "assuan-defs.h"
33 /* Extended version of write(2) to guarantee that all bytes are
34 written. Returns 0 on success or -1 and ERRNO on failure. */
35 static int
36 writen (assuan_context_t ctx, const char *buffer, size_t length)
38 while (length)
40 ssize_t nwritten = ctx->io->writefnc (ctx, buffer, length);
42 if (nwritten < 0)
44 if (errno == EINTR)
45 continue;
46 return -1; /* write error */
48 length -= nwritten;
49 buffer += nwritten;
51 return 0; /* okay */
54 /* Read an entire line. Returns 0 on success or -1 and ERRNO on
55 failure. EOF is indictated by setting the integer at address
56 R_EOF. Note: BUF, R_NREAD and R_EOF contain a valid result even if
57 an error is returned. */
58 static int
59 readline (assuan_context_t ctx, char *buf, size_t buflen,
60 int *r_nread, int *r_eof)
62 size_t nleft = buflen;
63 char *p;
65 *r_eof = 0;
66 *r_nread = 0;
67 while (nleft > 0)
69 ssize_t n = ctx->io->readfnc (ctx, buf, nleft);
71 if (n < 0)
73 if (errno == EINTR)
74 continue;
75 return -1; /* read error */
77 else if (!n)
79 *r_eof = 1;
80 break; /* allow incomplete lines */
82 p = buf;
83 nleft -= n;
84 buf += n;
85 *r_nread += n;
87 p = memrchr (p, '\n', n);
88 if (p)
89 break; /* at least one full line available - that's enough for now */
92 return 0;
96 /* Function returns an Assuan error. */
97 assuan_error_t
98 _assuan_read_line (assuan_context_t ctx)
100 char *line = ctx->inbound.line;
101 int nread, atticlen;
102 int rc;
103 char *endp = 0;
105 if (ctx->inbound.eof)
106 return _assuan_error (-1);
108 atticlen = ctx->inbound.attic.linelen;
109 if (atticlen)
111 memcpy (line, ctx->inbound.attic.line, atticlen);
112 ctx->inbound.attic.linelen = 0;
114 endp = memchr (line, '\n', atticlen);
115 if (endp)
116 /* Found another line in the attic. */
118 rc = 0;
119 nread = atticlen;
120 atticlen = 0;
122 else
123 /* There is pending data but not a full line. */
125 assert (atticlen < LINELENGTH);
126 rc = readline (ctx, line + atticlen,
127 LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
130 else
131 /* No pending data. */
132 rc = readline (ctx, line, LINELENGTH,
133 &nread, &ctx->inbound.eof);
134 if (rc)
136 int saved_errno = errno;
138 if (ctx->log_fp)
139 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n",
140 assuan_get_assuan_log_prefix (),
141 (unsigned int)getpid (), (int)ctx->inbound.fd,
142 strerror (errno));
144 if (saved_errno == EAGAIN)
146 /* We have to save a partial line. */
147 memcpy (ctx->inbound.attic.line, line, atticlen + nread);
148 ctx->inbound.attic.pending = 0;
149 ctx->inbound.attic.linelen = atticlen + nread;
152 errno = saved_errno;
153 return _assuan_error (ASSUAN_Read_Error);
155 if (!nread)
157 assert (ctx->inbound.eof);
158 if (ctx->log_fp)
159 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n",
160 assuan_get_assuan_log_prefix (),
161 (unsigned int)getpid (), (int)ctx->inbound.fd);
162 return _assuan_error (-1);
165 ctx->inbound.attic.pending = 0;
166 nread += atticlen;
168 if (! endp)
169 endp = memchr (line, '\n', nread);
171 if (endp)
173 unsigned monitor_result;
174 int n = endp - line + 1;
176 if (n < nread)
177 /* LINE contains more than one line. We copy it to the attic
178 now as handlers are allowed to modify the passed
179 buffer. */
181 int len = nread - n;
182 memcpy (ctx->inbound.attic.line, endp + 1, len);
183 ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0;
184 ctx->inbound.attic.linelen = len;
187 if (endp != line && endp[-1] == '\r')
188 endp --;
189 *endp = 0;
191 ctx->inbound.linelen = endp - line;
193 monitor_result = (ctx->io_monitor
194 ? ctx->io_monitor (ctx, 0,
195 ctx->inbound.line,
196 ctx->inbound.linelen)
197 : 0);
198 if ( (monitor_result & 2) )
199 ctx->inbound.linelen = 0;
201 if (ctx->log_fp && !(monitor_result & 1))
203 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- ",
204 assuan_get_assuan_log_prefix (),
205 (unsigned int)getpid (), (int)ctx->inbound.fd);
206 if (ctx->confidential)
207 fputs ("[Confidential data not shown]", ctx->log_fp);
208 else
209 _assuan_log_print_buffer (ctx->log_fp,
210 ctx->inbound.line,
211 ctx->inbound.linelen);
212 putc ('\n', ctx->log_fp);
214 return 0;
216 else
218 if (ctx->log_fp)
219 fprintf (ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n",
220 assuan_get_assuan_log_prefix (),
221 (unsigned int)getpid (), (int)ctx->inbound.fd);
222 *line = 0;
223 ctx->inbound.linelen = 0;
224 return _assuan_error (ctx->inbound.eof
225 ? ASSUAN_Line_Not_Terminated
226 : ASSUAN_Line_Too_Long);
231 /* Read the next line from the client or server and return a pointer
232 in *LINE to a buffer holding the line. LINELEN is the length of
233 *LINE. The buffer is valid until the next read operation on it.
234 The caller may modify the buffer. The buffer is invalid (i.e. must
235 not be used) if an error is returned.
237 Returns 0 on success or an assuan error code.
238 See also: assuan_pending_line().
240 assuan_error_t
241 assuan_read_line (assuan_context_t ctx, char **line, size_t *linelen)
243 assuan_error_t err;
245 if (!ctx)
246 return _assuan_error (ASSUAN_Invalid_Value);
250 err = _assuan_read_line (ctx);
252 while (_assuan_error_is_eagain (err));
254 *line = ctx->inbound.line;
255 *linelen = ctx->inbound.linelen;
256 return err;
260 /* Return true if a full line is buffered (i.e. an entire line may be
261 read without any I/O). */
263 assuan_pending_line (assuan_context_t ctx)
265 return ctx && ctx->inbound.attic.pending;
269 assuan_error_t
270 _assuan_write_line (assuan_context_t ctx, const char *prefix,
271 const char *line, size_t len)
273 assuan_error_t rc = 0;
274 size_t prefixlen = prefix? strlen (prefix):0;
275 unsigned int monitor_result;
277 /* Make sure that the line is short enough. */
278 if (len + prefixlen + 2 > ASSUAN_LINELENGTH)
280 if (ctx->log_fp)
281 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
282 "[supplied line too long -truncated]\n",
283 assuan_get_assuan_log_prefix (),
284 (unsigned int)getpid (), (int)ctx->inbound.fd);
285 if (prefixlen > 5)
286 prefixlen = 5;
287 if (len > ASSUAN_LINELENGTH - prefixlen - 2)
288 len = ASSUAN_LINELENGTH - prefixlen - 2 - 1;
291 monitor_result = (ctx->io_monitor
292 ? ctx->io_monitor (ctx, 1, line, len)
293 : 0);
295 /* Fixme: we should do some kind of line buffering. */
296 if (ctx->log_fp && !(monitor_result & 1))
298 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
299 assuan_get_assuan_log_prefix (),
300 (unsigned int)getpid (), (int)ctx->inbound.fd);
301 if (ctx->confidential)
302 fputs ("[Confidential data not shown]", ctx->log_fp);
303 else
305 if (prefixlen)
306 _assuan_log_print_buffer (ctx->log_fp, prefix, prefixlen);
307 _assuan_log_print_buffer (ctx->log_fp, line, len);
309 putc ('\n', ctx->log_fp);
312 if (prefixlen && !(monitor_result & 2))
314 rc = writen (ctx, prefix, prefixlen);
315 if (rc)
316 rc = _assuan_error (ASSUAN_Write_Error);
318 if (!rc && !(monitor_result & 2))
320 rc = writen (ctx, line, len);
321 if (rc)
322 rc = _assuan_error (ASSUAN_Write_Error);
323 if (!rc)
325 rc = writen (ctx, "\n", 1);
326 if (rc)
327 rc = _assuan_error (ASSUAN_Write_Error);
330 return rc;
334 assuan_error_t
335 assuan_write_line (assuan_context_t ctx, const char *line)
337 size_t len;
338 const char *s;
340 if (!ctx)
341 return _assuan_error (ASSUAN_Invalid_Value);
343 /* Make sure that we never take a LF from the user - this might
344 violate the protocol. */
345 s = strchr (line, '\n');
346 len = s? (s-line) : strlen (line);
348 if (ctx->log_fp && s)
349 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> "
350 "[supplied line contained a LF - truncated]\n",
351 assuan_get_assuan_log_prefix (),
352 (unsigned int)getpid (), (int)ctx->inbound.fd);
354 return _assuan_write_line (ctx, NULL, line, len);
359 /* Write out the data in buffer as datalines with line wrapping and
360 percent escaping. This function is used for GNU's custom streams. */
362 _assuan_cookie_write_data (void *cookie, const char *buffer, size_t orig_size)
364 assuan_context_t ctx = cookie;
365 size_t size = orig_size;
366 char *line;
367 size_t linelen;
369 if (ctx->outbound.data.error)
370 return 0;
372 line = ctx->outbound.data.line;
373 linelen = ctx->outbound.data.linelen;
374 line += linelen;
375 while (size)
377 unsigned int monitor_result;
379 /* Insert data line header. */
380 if (!linelen)
382 *line++ = 'D';
383 *line++ = ' ';
384 linelen += 2;
387 /* Copy data, keep space for the CRLF and to escape one character. */
388 while (size && linelen < LINELENGTH-2-2)
390 if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
392 sprintf (line, "%%%02X", *(unsigned char*)buffer);
393 line += 3;
394 linelen += 3;
395 buffer++;
397 else
399 *line++ = *buffer++;
400 linelen++;
402 size--;
406 monitor_result = (ctx->io_monitor
407 ? ctx->io_monitor (ctx, 1,
408 ctx->outbound.data.line, linelen)
409 : 0);
411 if (linelen >= LINELENGTH-2-2)
413 if (ctx->log_fp && !(monitor_result & 1))
415 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
416 assuan_get_assuan_log_prefix (),
417 (unsigned int)getpid (), (int)ctx->inbound.fd);
419 if (ctx->confidential)
420 fputs ("[Confidential data not shown]", ctx->log_fp);
421 else
422 _assuan_log_print_buffer (ctx->log_fp,
423 ctx->outbound.data.line,
424 linelen);
425 putc ('\n', ctx->log_fp);
427 *line++ = '\n';
428 linelen++;
429 if ( !(monitor_result & 2)
430 && writen (ctx, ctx->outbound.data.line, linelen))
432 ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
433 return 0;
435 line = ctx->outbound.data.line;
436 linelen = 0;
440 ctx->outbound.data.linelen = linelen;
441 return (int)orig_size;
445 /* Write out any buffered data
446 This function is used for GNU's custom streams */
448 _assuan_cookie_write_flush (void *cookie)
450 assuan_context_t ctx = cookie;
451 char *line;
452 size_t linelen;
453 unsigned int monitor_result;
455 if (ctx->outbound.data.error)
456 return 0;
458 line = ctx->outbound.data.line;
459 linelen = ctx->outbound.data.linelen;
460 line += linelen;
462 monitor_result = (ctx->io_monitor
463 ? ctx->io_monitor (ctx, 1,
464 ctx->outbound.data.line, linelen)
465 : 0);
467 if (linelen)
469 if (ctx->log_fp && !(monitor_result & 1))
471 fprintf (ctx->log_fp, "%s[%u.%d] DBG: -> ",
472 assuan_get_assuan_log_prefix (),
473 (unsigned int)getpid (), (int)ctx->inbound.fd);
474 if (ctx->confidential)
475 fputs ("[Confidential data not shown]", ctx->log_fp);
476 else
477 _assuan_log_print_buffer (ctx->log_fp,
478 ctx->outbound.data.line, linelen);
479 putc ('\n', ctx->log_fp);
481 *line++ = '\n';
482 linelen++;
483 if ( !(monitor_result & 2)
484 && writen (ctx, ctx->outbound.data.line, linelen))
486 ctx->outbound.data.error = _assuan_error (ASSUAN_Write_Error);
487 return 0;
489 ctx->outbound.data.linelen = 0;
491 return 0;
496 * assuan_send_data:
497 * @ctx: An assuan context
498 * @buffer: Data to send or NULL to flush
499 * @length: length of the data to send/
501 * This function may be used by the server or the client to send data
502 * lines. The data will be escaped as required by the Assuan protocol
503 * and may get buffered until a line is full. To force sending the
504 * data out @buffer may be passed as NULL (in which case @length must
505 * also be 0); however when used by a client this flush operation does
506 * also send the terminating "END" command to terminate the reponse on
507 * a INQUIRE response. However, when assuan_transact() is used, this
508 * function takes care of sending END itself.
510 * Return value: 0 on success or an error code
513 assuan_error_t
514 assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
516 if (!ctx)
517 return _assuan_error (ASSUAN_Invalid_Value);
518 if (!buffer && length)
519 return _assuan_error (ASSUAN_Invalid_Value);
521 if (!buffer)
522 { /* flush what we have */
523 _assuan_cookie_write_flush (ctx);
524 if (ctx->outbound.data.error)
525 return ctx->outbound.data.error;
526 if (!ctx->is_server)
527 return assuan_write_line (ctx, "END");
529 else
531 _assuan_cookie_write_data (ctx, buffer, length);
532 if (ctx->outbound.data.error)
533 return ctx->outbound.data.error;
536 return 0;
539 assuan_error_t
540 assuan_sendfd (assuan_context_t ctx, assuan_fd_t fd)
542 /* It is explicitly allowed to use (NULL, -1) as a runtime test to
543 check whether descriptor passing is available. */
544 if (!ctx && fd == ASSUAN_INVALID_FD)
545 #ifdef USE_DESCRIPTOR_PASSING
546 return 0;
547 #else
548 return _assuan_error (ASSUAN_Not_Implemented);
549 #endif
551 if (! ctx->io->sendfd)
552 return set_error (ctx, Not_Implemented,
553 "server does not support sending and receiving "
554 "of file descriptors");
555 return ctx->io->sendfd (ctx, fd);
558 assuan_error_t
559 assuan_receivefd (assuan_context_t ctx, assuan_fd_t *fd)
561 if (! ctx->io->receivefd)
562 return set_error (ctx, Not_Implemented,
563 "server does not support sending and receiving "
564 "of file descriptors");
565 return ctx->io->receivefd (ctx, fd);