gpg_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, const char *line, size_t len) { gpg_error_t rc = 0; size_t prefixlen = prefix? strlen (prefix):0; unsigned int monitor_result; /* Make sure that the line is short enough. */ if (len + prefixlen + 2 > ASSUAN_LINELENGTH) { _assuan_log_control_channel (ctx, 1, "supplied line too long - truncated", NULL, 0, NULL, 0); if (prefixlen > 5) prefixlen = 5; if (len > ASSUAN_LINELENGTH - prefixlen - 2) len = ASSUAN_LINELENGTH - prefixlen - 2 - 1; } monitor_result = 0; if (ctx->io_monitor) monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 1, line, len); /* Fixme: we should do some kind of line buffering. */ if (!(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) _assuan_log_control_channel (ctx, 1, NULL, prefixlen? prefix:NULL, prefixlen, line, len); if (prefixlen && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)) { rc = writen (ctx, prefix, prefixlen); if (rc) rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); } if (!rc && !(monitor_result & ASSUAN_IO_MONITOR_IGNORE)) { rc = writen (ctx, line, len); if (rc) rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); if (!rc) { rc = writen (ctx, "\n", 1); if (rc) rc = _assuan_error (ctx, gpg_err_code_from_syserror ()); } } return rc; }
/* Function returns an Assuan error. */ assuan_error_t _assuan_read_line(assuan_context_t ctx) { char *line = ctx->inbound.line; int nread, atticlen; int rc; char *endp = 0; if(ctx->inbound.eof) return _assuan_error(-1); atticlen = ctx->inbound.attic.linelen; if(atticlen) { memcpy(line, ctx->inbound.attic.line, atticlen); ctx->inbound.attic.linelen = 0; endp = memchr(line, '\n', atticlen); if(endp) /* Found another line in the attic. */ { rc = 0; nread = atticlen; atticlen = 0; } else /* There is pending data but not a full line. */ { assert(atticlen < LINELENGTH); rc = readline(ctx, line + atticlen, LINELENGTH - atticlen, &nread, &ctx->inbound.eof); } } else /* No pending data. */ rc = readline(ctx, line, LINELENGTH, &nread, &ctx->inbound.eof); if(rc) { if(ctx->log_fp) fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [Error: %s]\n", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd, strerror(errno)); return _assuan_error(ASSUAN_Read_Error); } if(!nread) { assert(ctx->inbound.eof); if(ctx->log_fp) fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [EOF]\n", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd); return _assuan_error(-1); } ctx->inbound.attic.pending = 0; nread += atticlen; if(! endp) endp = memchr(line, '\n', nread); if(endp) { unsigned monitor_result; int n = endp - line + 1; if(n < nread) /* LINE contains more than one line. We copy it to the attic now as handlers are allowed to modify the passed buffer. */ { int len = nread - n; memcpy(ctx->inbound.attic.line, endp + 1, len); ctx->inbound.attic.pending = memrchr(endp + 1, '\n', len) ? 1 : 0; ctx->inbound.attic.linelen = len; } if(endp != line && endp[-1] == '\r') endp --; *endp = 0; ctx->inbound.linelen = endp - line; monitor_result = (ctx->io_monitor ? ctx->io_monitor(ctx, 0, ctx->inbound.line, ctx->inbound.linelen) : 0); if((monitor_result & 2)) ctx->inbound.linelen = 0; if(ctx->log_fp && !(monitor_result & 1)) { fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- ", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd); if(ctx->confidential) fputs("[Confidential data not shown]", ctx->log_fp); else _assuan_log_print_buffer(ctx->log_fp, ctx->inbound.line, ctx->inbound.linelen); putc('\n', ctx->log_fp); } return 0; } else { if(ctx->log_fp) fprintf(ctx->log_fp, "%s[%u.%d] DBG: <- [Invalid line]\n", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd); *line = 0; ctx->inbound.linelen = 0; return _assuan_error(ctx->inbound.eof ? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long); } }
/* Read a line with buffering of partial lines. Function returns an Assuan error. */ gpg_error_t _assuan_read_line (assuan_context_t ctx) { gpg_error_t rc = 0; char *line = ctx->inbound.line; int nread, atticlen; char *endp = 0; if (ctx->inbound.eof) return _assuan_error (ctx, GPG_ERR_EOF); atticlen = ctx->inbound.attic.linelen; if (atticlen) { memcpy (line, ctx->inbound.attic.line, atticlen); ctx->inbound.attic.linelen = 0; endp = memchr (line, '\n', atticlen); if (endp) { /* Found another line in the attic. */ nread = atticlen; atticlen = 0; } else { /* There is pending data but not a full line. */ assert (atticlen < LINELENGTH); rc = readline (ctx, line + atticlen, LINELENGTH - atticlen, &nread, &ctx->inbound.eof); } } else /* No pending data. */ rc = readline (ctx, line, LINELENGTH, &nread, &ctx->inbound.eof); if (rc) { int saved_errno = errno; char buf[100]; snprintf (buf, sizeof buf, "error: %s", strerror (errno)); _assuan_log_control_channel (ctx, 0, buf, NULL, 0, NULL, 0); if (saved_errno == EAGAIN) { /* We have to save a partial line. Due to readline's behaviour, we know that this is not a complete line yet (no newline). So we don't set PENDING to true. */ memcpy (ctx->inbound.attic.line, line, atticlen + nread); ctx->inbound.attic.pending = 0; ctx->inbound.attic.linelen = atticlen + nread; } gpg_err_set_errno (saved_errno); return _assuan_error (ctx, gpg_err_code_from_syserror ()); } if (!nread) { assert (ctx->inbound.eof); _assuan_log_control_channel (ctx, 0, "eof", NULL, 0, NULL, 0); return _assuan_error (ctx, GPG_ERR_EOF); } ctx->inbound.attic.pending = 0; nread += atticlen; if (! endp) endp = memchr (line, '\n', nread); if (endp) { unsigned monitor_result; int n = endp - line + 1; if (n < nread) /* LINE contains more than one line. We copy it to the attic now as handlers are allowed to modify the passed buffer. */ { int len = nread - n; memcpy (ctx->inbound.attic.line, endp + 1, len); ctx->inbound.attic.pending = memrchr (endp + 1, '\n', len) ? 1 : 0; ctx->inbound.attic.linelen = len; } if (endp != line && endp[-1] == '\r') endp --; *endp = 0; ctx->inbound.linelen = endp - line; monitor_result = 0; if (ctx->io_monitor) monitor_result = ctx->io_monitor (ctx, ctx->io_monitor_data, 0, ctx->inbound.line, ctx->inbound.linelen); if (monitor_result & ASSUAN_IO_MONITOR_IGNORE) ctx->inbound.linelen = 0; if ( !(monitor_result & ASSUAN_IO_MONITOR_NOLOG)) _assuan_log_control_channel (ctx, 0, NULL, ctx->inbound.line, ctx->inbound.linelen, NULL, 0); return 0; } else { _assuan_log_control_channel (ctx, 0, "invalid line", NULL, 0, NULL, 0); *line = 0; ctx->inbound.linelen = 0; return _assuan_error (ctx, ctx->inbound.eof ? GPG_ERR_ASS_INCOMPLETE_LINE : GPG_ERR_ASS_LINE_TOO_LONG); } }
assuan_error_t _assuan_write_line(assuan_context_t ctx, const char *prefix, const char *line, size_t len) { assuan_error_t rc = 0; size_t prefixlen = prefix ? strlen(prefix) : 0; unsigned int monitor_result; /* Make sure that the line is short enough. */ if(len + prefixlen + 2 > ASSUAN_LINELENGTH) { if(ctx->log_fp) fprintf(ctx->log_fp, "%s[%u.%d] DBG: -> " "[supplied line too long -truncated]\n", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd); if(prefixlen > 5) prefixlen = 5; if(len > ASSUAN_LINELENGTH - prefixlen - 2) len = ASSUAN_LINELENGTH - prefixlen - 2 - 1; } monitor_result = (ctx->io_monitor ? ctx->io_monitor(ctx, 1, line, len) : 0); /* Fixme: we should do some kind of line buffering. */ if(ctx->log_fp && !(monitor_result & 1)) { fprintf(ctx->log_fp, "%s[%u.%d] DBG: -> ", assuan_get_assuan_log_prefix(), (unsigned int)getpid(), ctx->inbound.fd); if(ctx->confidential) fputs("[Confidential data not shown]", ctx->log_fp); else { if(prefixlen) _assuan_log_print_buffer(ctx->log_fp, prefix, prefixlen); _assuan_log_print_buffer(ctx->log_fp, line, len); } putc('\n', ctx->log_fp); } if(prefixlen && !(monitor_result & 2)) { rc = writen(ctx, prefix, prefixlen); if(rc) rc = _assuan_error(ASSUAN_Write_Error); } if(!rc && !(monitor_result & 2)) { rc = writen(ctx, line, len); if(rc) rc = _assuan_error(ASSUAN_Write_Error); if(!rc) { rc = writen(ctx, "\n", 1); if(rc) rc = _assuan_error(ASSUAN_Write_Error); } } return rc; }