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 (_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
)
372 line
= ctx
->outbound
.data
.line
;
373 linelen
= ctx
->outbound
.data
.linelen
;
377 unsigned int monitor_result
;
379 /* Insert data line header. */
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
);
406 monitor_result
= (ctx
->io_monitor
407 ? ctx
->io_monitor (ctx
, 1,
408 ctx
->outbound
.data
.line
, linelen
)
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
);
422 _assuan_log_print_buffer (ctx
->log_fp
,
423 ctx
->outbound
.data
.line
,
425 putc ('\n', ctx
->log_fp
);
429 if ( !(monitor_result
& 2)
430 && writen (ctx
, ctx
->outbound
.data
.line
, linelen
))
432 ctx
->outbound
.data
.error
= _assuan_error (ASSUAN_Write_Error
);
435 line
= ctx
->outbound
.data
.line
;
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
;
453 unsigned int monitor_result
;
455 if (ctx
->outbound
.data
.error
)
458 line
= ctx
->outbound
.data
.line
;
459 linelen
= ctx
->outbound
.data
.linelen
;
462 monitor_result
= (ctx
->io_monitor
463 ? ctx
->io_monitor (ctx
, 1,
464 ctx
->outbound
.data
.line
, 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
);
477 _assuan_log_print_buffer (ctx
->log_fp
,
478 ctx
->outbound
.data
.line
, linelen
);
479 putc ('\n', ctx
->log_fp
);
483 if ( !(monitor_result
& 2)
484 && writen (ctx
, ctx
->outbound
.data
.line
, linelen
))
486 ctx
->outbound
.data
.error
= _assuan_error (ASSUAN_Write_Error
);
489 ctx
->outbound
.data
.linelen
= 0;
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 * If BUFFER is NULL and LENGTH is 1 and we are a client, a "CAN" is
511 * send instead of an "END".
513 * Return value: 0 on success or an error code
517 assuan_send_data (assuan_context_t ctx
, const void *buffer
, size_t length
)
520 return _assuan_error (ASSUAN_Invalid_Value
);
521 if (!buffer
&& length
> 1)
522 return _assuan_error (ASSUAN_Invalid_Value
);
525 { /* flush what we have */
526 _assuan_cookie_write_flush (ctx
);
527 if (ctx
->outbound
.data
.error
)
528 return ctx
->outbound
.data
.error
;
530 return assuan_write_line (ctx
, length
== 1? "CAN":"END");
534 _assuan_cookie_write_data (ctx
, buffer
, length
);
535 if (ctx
->outbound
.data
.error
)
536 return ctx
->outbound
.data
.error
;
543 assuan_sendfd (assuan_context_t ctx
, assuan_fd_t fd
)
545 /* It is explicitly allowed to use (NULL, -1) as a runtime test to
546 check whether descriptor passing is available. */
547 if (!ctx
&& fd
== ASSUAN_INVALID_FD
)
548 #ifdef USE_DESCRIPTOR_PASSING
551 return _assuan_error (ASSUAN_Not_Implemented
);
554 if (! ctx
->io
->sendfd
)
555 return set_error (ctx
, Not_Implemented
,
556 "server does not support sending and receiving "
557 "of file descriptors");
558 return ctx
->io
->sendfd (ctx
, fd
);
562 assuan_receivefd (assuan_context_t ctx
, assuan_fd_t
*fd
)
564 if (! ctx
->io
->receivefd
)
565 return set_error (ctx
, Not_Implemented
,
566 "server does not support sending and receiving "
567 "of file descriptors");
568 return ctx
->io
->receivefd (ctx
, fd
);