common: Add stream interface to call-pgp.
authorJustus Winter <justus@g10code.com>
Tue, 24 Nov 2015 17:31:14 +0000 (18:31 +0100)
committerJustus Winter <justus@g10code.com>
Wed, 25 Nov 2015 11:19:50 +0000 (12:19 +0100)
* common/call-gpg.c (struct writer_thread_parms): Add field 'stream'.
(writer_thread_main): Support reading from a stream.
(start_writer): Add stream argument.
(struct reader_thread_parms): Add field 'stream'.
(reader_thread_main): Support writing to a stream.
(start_reader): Add stream argument.
(_gpg_encrypt): Add stream api.
(gpg_encrypt_blob): Adapt accordingly.
(gpg_encrypt_stream): New function.
(_gpg_decrypt): Add stream api.
(gpg_decrypt_blob): Adapt accordingly.
(gpg_decrypt_stream): New function.
* common/call-gpg.h (gpg_encrypt_stream): New prototype.
(gpg_decrypt_stream): Likewise.

Signed-off-by: Justus Winter <justus@g10code.com>
common/call-gpg.c
common/call-gpg.h

index cc6b1e8..8258b83 100644 (file)
@@ -151,6 +151,7 @@ struct writer_thread_parms
   int fd;
   const void *data;
   size_t datalen;
+  estream_t stream;
   gpg_error_t *err_addr;
 };
 
@@ -159,9 +160,27 @@ struct writer_thread_parms
 static void *
 writer_thread_main (void *arg)
 {
+  gpg_error_t err = 0;
   struct writer_thread_parms *parm = arg;
-  const char *buffer = parm->data;
-  size_t length = parm->datalen;
+  char _buffer[4096];
+  char *buffer;
+  size_t length;
+
+  if (parm->stream)
+    {
+      buffer = _buffer;
+      err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+      if (err)
+        {
+          log_error ("reading stream failed: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+    }
+  else
+    {
+      buffer = (char *) parm->data;
+      length = parm->datalen;
+    }
 
   while (length)
     {
@@ -172,13 +191,33 @@ writer_thread_main (void *arg)
         {
           if (errno == EINTR)
             continue;
-          *parm->err_addr = gpg_error_from_syserror ();
+          err = gpg_error_from_syserror ();
           break; /* Write error.  */
         }
       length -= nwritten;
-      buffer += nwritten;
+
+      if (parm->stream)
+        {
+          if (length == 0)
+            {
+              err = es_read (parm->stream, buffer, sizeof _buffer, &length);
+              if (err)
+                {
+                  log_error ("reading stream failed: %s\n",
+                             gpg_strerror (err));
+                  break;
+                }
+              if (length == 0)
+                /* We're done.  */
+                break;
+            }
+        }
+      else
+        buffer += nwritten;
     }
 
+ leave:
+  *parm->err_addr = err;
   if (close (parm->fd))
     log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
   xfree (parm);
@@ -192,7 +231,7 @@ writer_thread_main (void *arg)
    variable to receive a possible write error after the thread has
    finished.  */
 static gpg_error_t
-start_writer (int fd, const void *data, size_t datalen,
+start_writer (int fd, const void *data, size_t datalen, estream_t stream,
               npth_t *r_thread, gpg_error_t *err_addr)
 {
   gpg_error_t err;
@@ -210,6 +249,7 @@ start_writer (int fd, const void *data, size_t datalen,
   parm->fd = fd;
   parm->data = data;
   parm->datalen = datalen;
+  parm->stream = stream;
   parm->err_addr = err_addr;
 
   npth_attr_init (&tattr);
@@ -239,6 +279,7 @@ struct reader_thread_parms
 {
   int fd;
   membuf_t *mb;
+  estream_t stream;
   gpg_error_t *err_addr;
 };
 
@@ -247,6 +288,7 @@ struct reader_thread_parms
 static void *
 reader_thread_main (void *arg)
 {
+  gpg_error_t err = 0;
   struct reader_thread_parms *parm = arg;
   char buffer[4096];
   int nread;
@@ -257,13 +299,33 @@ reader_thread_main (void *arg)
         {
           if (errno == EINTR)
             continue;
-          *parm->err_addr = gpg_error_from_syserror ();
+          err = gpg_error_from_syserror ();
           break;  /* Read error.  */
         }
 
-      put_membuf (parm->mb, buffer, nread);
+      if (parm->stream)
+        {
+          const char *p = buffer;
+          size_t nwritten;
+          while (nread)
+            {
+              err = es_write (parm->stream, p, nread, &nwritten);
+              if (err)
+                {
+                  log_error ("writing stream failed: %s\n",
+                             gpg_strerror (err));
+                  goto leave;
+                }
+              nread -= nwritten;
+              p += nwritten;
+            }
+        }
+      else
+        put_membuf (parm->mb, buffer, nread);
     }
 
+ leave:
+  *parm->err_addr = err;
   if (close (parm->fd))
     log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
   xfree (parm);
@@ -276,7 +338,8 @@ reader_thread_main (void *arg)
    is stored at R_TID.  After the thread has finished an error from
    the thread will be stored at ERR_ADDR.  */
 static gpg_error_t
-start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
+start_reader (int fd, membuf_t *mb, estream_t stream,
+              npth_t *r_thread, gpg_error_t *err_addr)
 {
   gpg_error_t err;
   struct reader_thread_parms *parm;
@@ -292,6 +355,7 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
     return gpg_error_from_syserror ();
   parm->fd = fd;
   parm->mb = mb;
+  parm->stream = stream;
   parm->err_addr = err_addr;
 
   npth_attr_init (&tattr);
@@ -324,8 +388,10 @@ start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
 static gpg_error_t
 _gpg_encrypt (ctrl_t ctrl, const char *gpg_program,
               const void *plain, size_t plainlen,
+              estream_t plain_stream,
               strlist_t keys,
-              membuf_t *reader_mb)
+              membuf_t *reader_mb,
+              estream_t cipher_stream)
 {
   gpg_error_t err;
   assuan_context_t ctx = NULL;
@@ -338,6 +404,11 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program,
   strlist_t sl;
   int ret;
 
+  /* Make sure that either the stream interface xor the buffer
+     interface is used.  */
+  assert ((plain == NULL) != (plain_stream == NULL));
+  assert ((reader_mb == NULL) != (cipher_stream == NULL));
+
   /* Create two pipes.  */
   err = gnupg_create_outbound_pipe (outbound_fds);
   if (!err)
@@ -356,7 +427,7 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program,
   close (inbound_fds[1]); inbound_fds[1] = -1;
 
   /* Start a writer thread to feed the INPUT command of the server.  */
-  err = start_writer (outbound_fds[1], plain, plainlen,
+  err = start_writer (outbound_fds[1], plain, plainlen, plain_stream,
                       &writer_thread, &writer_err);
   if (err)
     return err;
@@ -364,7 +435,7 @@ _gpg_encrypt (ctrl_t ctrl, const char *gpg_program,
 
   /* Start a reader thread to eat from the OUTPUT command of the
      server.  */
-  err = start_reader (inbound_fds[0], reader_mb,
+  err = start_reader (inbound_fds[0], reader_mb, cipher_stream,
                       &reader_thread, &reader_err);
   if (err)
     return err;
@@ -458,9 +529,9 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program,
   init_membuf (&reader_mb, 4096);
 
   err = _gpg_encrypt (ctrl, gpg_program,
-                      plain, plainlen,
+                      plain, plainlen, NULL,
                       keys,
-                      &reader_mb);
+                      &reader_mb, NULL);
 
   if (! err)
     {
@@ -478,6 +549,17 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program,
   return err;
 }
 
+gpg_error_t
+gpg_encrypt_stream (ctrl_t ctrl, const char *gpg_program,
+                    estream_t plain_stream,
+                    strlist_t keys,
+                    estream_t cipher_stream)
+{
+  return _gpg_encrypt (ctrl, gpg_program,
+                       NULL, 0, plain_stream,
+                       keys,
+                       NULL, cipher_stream);
+}
 \f
 /* Call GPG to decrypt a block of data.
 
@@ -486,7 +568,9 @@ gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program,
 static gpg_error_t
 _gpg_decrypt (ctrl_t ctrl, const char *gpg_program,
               const void *ciph, size_t ciphlen,
-              membuf_t *reader_mb)
+              estream_t cipher_stream,
+              membuf_t *reader_mb,
+              estream_t plain_stream)
 {
   gpg_error_t err;
   assuan_context_t ctx = NULL;
@@ -497,6 +581,11 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program,
   gpg_error_t writer_err, reader_err;
   int ret;
 
+  /* Make sure that either the stream interface xor the buffer
+     interface is used.  */
+  assert ((ciph == NULL) != (cipher_stream == NULL));
+  assert ((reader_mb == NULL) != (plain_stream == NULL));
+
   /* Create two pipes.  */
   err = gnupg_create_outbound_pipe (outbound_fds);
   if (!err)
@@ -515,7 +604,7 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program,
   close (inbound_fds[1]); inbound_fds[1] = -1;
 
   /* Start a writer thread to feed the INPUT command of the server.  */
-  err = start_writer (outbound_fds[1], ciph, ciphlen,
+  err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream,
                       &writer_thread, &writer_err);
   if (err)
     return err;
@@ -523,7 +612,7 @@ _gpg_decrypt (ctrl_t ctrl, const char *gpg_program,
 
   /* Start a reader thread to eat from the OUTPUT command of the
      server.  */
-  err = start_reader (inbound_fds[0], reader_mb,
+  err = start_reader (inbound_fds[0], reader_mb, plain_stream,
                       &reader_thread, &reader_err);
   if (err)
     return err;
@@ -602,8 +691,8 @@ gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program,
   init_membuf_secure (&reader_mb, 1024);
 
   err = _gpg_decrypt (ctrl, gpg_program,
-                      ciph, ciphlen,
-                      &reader_mb);
+                      ciph, ciphlen, NULL,
+                      &reader_mb, NULL);
 
   if (! err)
     {
@@ -620,3 +709,13 @@ gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program,
   xfree (get_membuf (&reader_mb, NULL));
   return err;
 }
+
+gpg_error_t
+gpg_decrypt_stream (ctrl_t ctrl, const char *gpg_program,
+                    estream_t cipher_stream,
+                    estream_t plain_stream)
+{
+  return _gpg_decrypt (ctrl, gpg_program,
+                       NULL, 0, cipher_stream,
+                       NULL, plain_stream);
+}
index 606473d..2c5854d 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef G13_CALL_GPG_H
 #define G13_CALL_GPG_H
 
+#include <gpg-error.h>
+
 #include "strlist.h"
 
 typedef struct server_control_s *ctrl_t;
@@ -28,10 +30,18 @@ gpg_error_t gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program,
                               const void *plain, size_t plainlen,
                               strlist_t keys,
                               void **r_ciph, size_t *r_ciphlen);
+
+gpg_error_t gpg_encrypt_stream (ctrl_t ctrl, const char *gpg_program,
+                               estream_t plain_stream,
+                               strlist_t keys,
+                               estream_t cipher_stream);
+
 gpg_error_t gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program,
                              const void *ciph, size_t ciphlen,
                               void **r_plain, size_t *r_plainlen);
 
-
+gpg_error_t gpg_decrypt_stream (ctrl_t ctrl, const char *gpg_program,
+                               estream_t cipher_stream,
+                               estream_t plain_stream);
 
 #endif /*G13_CALL_GPG_H*/