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/>.
27 #ifdef HAVE_W32_SYSTEM
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. */
36 writen (assuan_context_t ctx
, const char *buffer
, size_t length
)
40 ssize_t nwritten
= ctx
->io
->writefnc (ctx
, buffer
, length
);
46 return -1; /* write error */
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. */
59 readline (assuan_context_t ctx
, char *buf
, size_t buflen
,
60 int *r_nread
, int *r_eof
)
62 size_t nleft
= buflen
;
69 ssize_t n
= ctx
->io
->readfnc (ctx
, buf
, nleft
);
75 return -1; /* read error */
80 break; /* allow incomplete lines */
87 p
= memrchr (p
, '\n', n
);
89 break; /* at least one full line available - that's enough for now */
96 /* Function returns an Assuan error. */
98 _assuan_read_line (assuan_context_t ctx
)
100 char *line
= ctx
->inbound
.line
;
105 if (ctx
->inbound
.eof
)
106 return _assuan_error (-1);
108 atticlen
= ctx
->inbound
.attic
.linelen
;
111 memcpy (line
, ctx
->inbound
.attic
.line
, atticlen
);
112 ctx
->inbound
.attic
.linelen
= 0;
114 endp
= memchr (line
, '\n', atticlen
);
116 /* Found another line in the attic. */
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
);
131 /* No pending data. */
132 rc
= readline (ctx
, line
, LINELENGTH
,
133 &nread
, &ctx
->inbound
.eof
);
136 int saved_errno
= errno
;
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
,
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
;
153 return _assuan_error (ASSUAN_Read_Error
);
157 assert (ctx
->inbound
.eof
);
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;
169 endp
= memchr (line
, '\n', nread
);
173 unsigned monitor_result
;
174 int n
= endp
- line
+ 1;
177 /* LINE contains more than one line. We copy it to the attic
178 now as handlers are allowed to modify the passed
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')
191 ctx
->inbound
.linelen
= endp
- line
;
193 monitor_result
= (ctx
->io_monitor
194 ? ctx
->io_monitor (ctx
, 0,
196 ctx
->inbound
.linelen
)
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
);
209 _assuan_log_print_buffer (ctx
->log_fp
,
211 ctx
->inbound
.linelen
);
212 putc ('\n', 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
);
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().
241 assuan_read_line (assuan_context_t ctx
, char **line
, size_t *linelen
)
246 return _assuan_error (ASSUAN_Invalid_Value
);
250 err
= _assuan_read_line (ctx
);
252 while (!ctx
->in_inquire
&& _assuan_error_is_eagain (err
));
254 *line
= ctx
->inbound
.line
;
255 *linelen
= ctx
->inbound
.linelen
;
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
;
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
)
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
);
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
)
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
);
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
);
316 rc
= _assuan_error (ASSUAN_Write_Error
);
318 if (!rc
&& !(monitor_result
& 2))
320 rc
= writen (ctx
, line
, len
);
322 rc
= _assuan_error (ASSUAN_Write_Error
);
325 rc
= writen (ctx
, "\n", 1);
327 rc
= _assuan_error (ASSUAN_Write_Error
);
335 assuan_write_line (assuan_context_t ctx
, const char *line
)
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
;
369 if (ctx
->outbound
.data
.error
) {
370 if (_assuan_error_is_eagain(ctx
->outbound
.data
.error
))
371 ctx
->outbound
.data
.error
= 0;
376 line
= ctx
->outbound
.data
.line
;
377 linelen
= ctx
->outbound
.data
.linelen
;
381 unsigned int monitor_result
;
383 /* Insert data line header. */
391 /* Copy data, keep space for the CRLF and to escape one character. */
392 while (size
&& linelen
< LINELENGTH
-2-2)
394 if (*buffer
== '%' || *buffer
== '\r' || *buffer
== '\n')
396 sprintf (line
, "%%%02X", *(unsigned char*)buffer
);
410 monitor_result
= (ctx
->io_monitor
411 ? ctx
->io_monitor (ctx
, 1,
412 ctx
->outbound
.data
.line
, linelen
)
415 if (linelen
>= LINELENGTH
-2-2)
417 if (ctx
->log_fp
&& !(monitor_result
& 1))
419 fprintf (ctx
->log_fp
, "%s[%u.%d] DBG: -> ",
420 assuan_get_assuan_log_prefix (),
421 (unsigned int)getpid (), (int)ctx
->inbound
.fd
);
423 if (ctx
->confidential
)
424 fputs ("[Confidential data not shown]", ctx
->log_fp
);
426 _assuan_log_print_buffer (ctx
->log_fp
,
427 ctx
->outbound
.data
.line
,
429 putc ('\n', ctx
->log_fp
);
433 if ( !(monitor_result
& 2)
434 && writen (ctx
, ctx
->outbound
.data
.line
, linelen
))
436 ctx
->outbound
.data
.error
= _assuan_error (ASSUAN_Write_Error
);
439 line
= ctx
->outbound
.data
.line
;
444 ctx
->outbound
.data
.linelen
= linelen
;
445 return (int)orig_size
;
449 /* Write out any buffered data
450 This function is used for GNU's custom streams */
452 _assuan_cookie_write_flush (void *cookie
)
454 assuan_context_t ctx
= cookie
;
457 unsigned int monitor_result
;
459 if (ctx
->outbound
.data
.error
)
462 line
= ctx
->outbound
.data
.line
;
463 linelen
= ctx
->outbound
.data
.linelen
;
466 monitor_result
= (ctx
->io_monitor
467 ? ctx
->io_monitor (ctx
, 1,
468 ctx
->outbound
.data
.line
, linelen
)
473 if (ctx
->log_fp
&& !(monitor_result
& 1))
475 fprintf (ctx
->log_fp
, "%s[%u.%d] DBG: -> ",
476 assuan_get_assuan_log_prefix (),
477 (unsigned int)getpid (), (int)ctx
->inbound
.fd
);
478 if (ctx
->confidential
)
479 fputs ("[Confidential data not shown]", ctx
->log_fp
);
481 _assuan_log_print_buffer (ctx
->log_fp
,
482 ctx
->outbound
.data
.line
, linelen
);
483 putc ('\n', ctx
->log_fp
);
487 if ( !(monitor_result
& 2)
488 && writen (ctx
, ctx
->outbound
.data
.line
, linelen
))
490 ctx
->outbound
.data
.error
= _assuan_error (ASSUAN_Write_Error
);
493 ctx
->outbound
.data
.linelen
= 0;
501 * @ctx: An assuan context
502 * @buffer: Data to send or NULL to flush
503 * @length: length of the data to send/
505 * This function may be used by the server or the client to send data
506 * lines. The data will be escaped as required by the Assuan protocol
507 * and may get buffered until a line is full. To force sending the
508 * data out @buffer may be passed as NULL (in which case @length must
509 * also be 0); however when used by a client this flush operation does
510 * also send the terminating "END" command to terminate the reponse on
511 * a INQUIRE response. However, when assuan_transact() is used, this
512 * function takes care of sending END itself.
514 * Return value: 0 on success or an error code
518 assuan_send_data (assuan_context_t ctx
, const void *buffer
, size_t length
)
521 return _assuan_error (ASSUAN_Invalid_Value
);
522 if (!buffer
&& length
)
523 return _assuan_error (ASSUAN_Invalid_Value
);
526 { /* flush what we have */
527 _assuan_cookie_write_flush (ctx
);
528 if (ctx
->outbound
.data
.error
)
529 return ctx
->outbound
.data
.error
;
531 return assuan_write_line (ctx
, "END");
535 _assuan_cookie_write_data (ctx
, buffer
, length
);
536 if (ctx
->outbound
.data
.error
)
537 return ctx
->outbound
.data
.error
;
544 assuan_sendfd (assuan_context_t ctx
, assuan_fd_t fd
)
546 /* It is explicitly allowed to use (NULL, -1) as a runtime test to
547 check whether descriptor passing is available. */
548 if (!ctx
&& fd
== ASSUAN_INVALID_FD
)
549 #ifdef USE_DESCRIPTOR_PASSING
552 return _assuan_error (ASSUAN_Not_Implemented
);
555 if (! ctx
->io
->sendfd
)
556 return set_error (ctx
, Not_Implemented
,
557 "server does not support sending and receiving "
558 "of file descriptors");
559 return ctx
->io
->sendfd (ctx
, fd
);
563 assuan_receivefd (assuan_context_t ctx
, assuan_fd_t
*fd
)
565 if (! ctx
->io
->receivefd
)
566 return set_error (ctx
, Not_Implemented
,
567 "server does not support sending and receiving "
568 "of file descriptors");
569 return ctx
->io
->receivefd (ctx
, fd
);