On Tue, Feb 14, 2017 at 04:41:00PM +0000, Niels Thykier wrote:
> Wouter Verhelst:
> > Hi Niels,
> > 
> > On Sun, Feb 12, 2017 at 08:52:00AM +0000, Niels Thykier wrote:
> >> Any news on this bug?
> > 
> > I'm going to release (upstream) nbd 3.15.2 later this week (probably on
> > thursday), which contains the fix:
> > 
> > https://github.com/NetworkBlockDevice/nbd/compare/nbd-3.15.1...master
> > 
> > This patch series includes:
> > 
> > - The fix for this bug, commit a43a2d8;
> > - Several minor documentation fixes (e.g., fixed the sorting of a listing 
> > in a
> >   man page);
> > - A better fix for the issue of nbd-client-udeb being compiled against 
> > GnuTLS
> >   that does not break the build on kFreeBSD etc;
> > - The ability to change the GnuTLS priority string, to follow TLS best
> >   practices and allow people to lock down the TLS configuration
> > 
> > I would like to update nbd to that version; but if the release team
> > prefers, I can cherry-pick a43a2d8 onto 3.15.1 and upload that instead.
> > 
> 
> Thanks for getting back to me on this.
> 
> On the note of the actual changes, could you please provide a (source)
> debdiff, so I know what we are looking at?

Attached.

Unfortunately, there's a bit of churn because I forgot to rename
nbd-3.15.1.tar.gz to nbd_3.15.1.orig.tar.gz, thereby causing it to be
uploaded as a native package, with a bit of stuff that shouldn't have
been in there. At least it didn't contain random junk like in the past,
but a .gitignore, some autotools metadata files, as well as a few files
that are meant to be shipped as symlinks rather than copies of files
from elsewhere in the tree (e.g., tests/run/buffer.c) do show up in the
debdiff.

If you ignore those, what remains is the changelog entry plus the
changes that I pointed to earlier.

Thanks for looking at this,

-- 
< ron> I mean, the main *practical* problem with C++, is there's like a dozen
       people in the world who think they really understand all of its rules,
       and pretty much all of them are just lying to themselves too.
 -- #debian-devel, OFTC, 2016-02-12
diff -Nru nbd-3.15.1/debian/changelog nbd-3.15.2/debian/changelog
--- nbd-3.15.1/debian/changelog 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/debian/changelog 2017-02-22 09:10:22.000000000 +0100
@@ -1,3 +1,12 @@
+nbd (1:3.15.2-1) unstable; urgency=medium
+
+  * New upstream release
+    - Fixes data corruption with multiple threads and copyonwrite enabled;
+      Closes: #852288, #849504. Why did I create multiple bugs for this?
+      Ah well, no matter.
+
+ -- Wouter Verhelst <wou...@debian.org>  Wed, 22 Feb 2017 00:09:31 +0100
+
 nbd (1:3.15.1-2) unstable; urgency=medium
 
   * Build nbd-client a second time with GnuTLS disabled, and install
diff -Nru nbd-3.15.1/.deps/libcliserv_la-cliserv.Plo 
nbd-3.15.2/.deps/libcliserv_la-cliserv.Plo
--- nbd-3.15.1/.deps/libcliserv_la-cliserv.Plo  2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/libcliserv_la-cliserv.Plo  1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/libnbdsrv_la-nbdsrv.Plo 
nbd-3.15.2/.deps/libnbdsrv_la-nbdsrv.Plo
--- nbd-3.15.1/.deps/libnbdsrv_la-nbdsrv.Plo    2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/libnbdsrv_la-nbdsrv.Plo    1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/libnbdsrv_la-treefiles.Plo 
nbd-3.15.2/.deps/libnbdsrv_la-treefiles.Plo
--- nbd-3.15.1/.deps/libnbdsrv_la-treefiles.Plo 2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/libnbdsrv_la-treefiles.Plo 1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/make-integrityhuge.Po 
nbd-3.15.2/.deps/make-integrityhuge.Po
--- nbd-3.15.1/.deps/make-integrityhuge.Po      2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/make-integrityhuge.Po      1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/nbd_client-buffer.Po 
nbd-3.15.2/.deps/nbd_client-buffer.Po
--- nbd-3.15.1/.deps/nbd_client-buffer.Po       2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/nbd_client-buffer.Po       1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/nbd_client-crypto-gnutls.Po 
nbd-3.15.2/.deps/nbd_client-crypto-gnutls.Po
--- nbd-3.15.1/.deps/nbd_client-crypto-gnutls.Po        2016-12-20 
20:36:11.000000000 +0100
+++ nbd-3.15.2/.deps/nbd_client-crypto-gnutls.Po        1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/nbd_client-nbd-client.Po 
nbd-3.15.2/.deps/nbd_client-nbd-client.Po
--- nbd-3.15.1/.deps/nbd_client-nbd-client.Po   2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/nbd_client-nbd-client.Po   1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/nbd_server-nbd-server.Po 
nbd-3.15.2/.deps/nbd_server-nbd-server.Po
--- nbd-3.15.1/.deps/nbd_server-nbd-server.Po   2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/nbd_server-nbd-server.Po   1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/.deps/nbd_trdump-nbd-trdump.Po 
nbd-3.15.2/.deps/nbd_trdump-nbd-trdump.Po
--- nbd-3.15.1/.deps/nbd_trdump-nbd-trdump.Po   2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/.deps/nbd_trdump-nbd-trdump.Po   1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/doc/proto.md nbd-3.15.2/doc/proto.md
--- nbd-3.15.1/doc/proto.md     2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/doc/proto.md     2017-02-14 02:13:30.000000000 +0100
@@ -307,7 +307,7 @@
   by the client.
 
 `NBD_CMD_FLUSH` is modelled on the Linux kernel empty bio with
-`REQ_FLUSH` set. `NBD_CMD_FLAG_FUA` is modelled on the Linux
+`REQ_PREFLUSH` set. `NBD_CMD_FLAG_FUA` is modelled on the Linux
 kernel bio with `REQ_FUA` set. In case of ambiguity in this
 specification, the
 [kernel 
documentation](https://www.kernel.org/doc/Documentation/block/writeback_cache_control.txt)
@@ -697,6 +697,8 @@
   the export.
 - bit 9, `NBD_FLAG_SEND_BLOCK_STATUS`: defined by the experimental
   `BLOCK_STATUS` 
[extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-blockstatus/doc/proto.md).
+- bit 10, `NBD_FLAG_SEND_RESIZE`: defined by the experimental `RESIZE`
+  
[extensio](https://github.com/NetworkBlockDevice/nbd/blob/extension-resize/doc/proto.md).
 
 Clients SHOULD ignore unknown flags.
 
@@ -989,6 +991,11 @@
     including one or more sectors beyond the size of the device. It SHOULD
     return `EPERM` if it receives a write zeroes request on a read-only export.
 
+* `NBD_CMD_RESIZE` (7)
+
+    Defined by the experimental `RESIZE`
+    
[extension](https://github.com/NetworkBlockDevice/nbd/blob/extension-resize/doc/proto.md).
+
 * Other requests
 
     Some third-party implementations may require additional protocol
diff -Nru nbd-3.15.1/.gitignore nbd-3.15.2/.gitignore
--- nbd-3.15.1/.gitignore       2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/.gitignore       1970-01-01 01:00:00.000000000 +0100
@@ -1,56 +0,0 @@
-.deps
-.dirstamp
-Makefile
-autom4te.cache
-autoscan.log
-config.h
-*~
-config.*
-file
-nbd-client.8
-nbd-server.1
-stamp-h.in
-stamp-h1
-Doxyfile
-compile
-manpage.refs
-manpage.links
-mkinstalldirs
-nbd-tester-client
-nbd-client
-nbd-server
-doc/doxygen-output
-nbd-server.config
-nbd-server.5
-nbd-trdump.1
-nbdtab.5
-*.o
-nbd-client.8.in
-nbd-server.1.in
-nbd-server.5.in
-nbd-trdump.1.in
-nbdtab.5.in
-Makefile.in
-config.h.in
-aclocal.m4
-INSTALL
-depcomp
-install-sh
-configure
-man/*.sh
-man/*.sh.in
-man/manpage.log
-make-integrityhuge
-nbd-trdump
-missing
-libtool
-*.lo
-ltmain.sh
-.libs/
-*.la
-support/lt*
-support/libtool.m4
-ar-lib
-tests/run/cliserv.c
-.debhelper
-*debhelper.log
diff -Nru nbd-3.15.1/gznbd/.deps/gznbd-gznbd.Po 
nbd-3.15.2/gznbd/.deps/gznbd-gznbd.Po
--- nbd-3.15.1/gznbd/.deps/gznbd-gznbd.Po       2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/gznbd/.deps/gznbd-gznbd.Po       1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/gznbd/.gitignore nbd-3.15.2/gznbd/.gitignore
--- nbd-3.15.1/gznbd/.gitignore 2013-12-23 20:34:24.000000000 +0100
+++ nbd-3.15.2/gznbd/.gitignore 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-gznbd
diff -Nru nbd-3.15.1/Makefile.am nbd-3.15.2/Makefile.am
--- nbd-3.15.1/Makefile.am      2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/Makefile.am      2017-02-22 09:10:22.000000000 +0100
@@ -38,3 +38,4 @@
 nbd_client_LDADD = $(client_libs)
 endif
 endif
+endif
diff -Nru nbd-3.15.1/man/manpage.links nbd-3.15.2/man/manpage.links
--- nbd-3.15.1/man/manpage.links        2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/man/manpage.links        1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-NBDTAB.5       $sysconfdir/nbdtab.5
diff -Nru nbd-3.15.1/man/manpage.refs nbd-3.15.2/man/manpage.refs
--- nbd-3.15.1/man/manpage.refs 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/man/manpage.refs 1970-01-01 01:00:00.000000000 +0100
@@ -1,4 +0,0 @@
-{
-  '' => '',
-  '' => ''
-}
diff -Nru nbd-3.15.1/man/nbd-server.5.in.sgml 
nbd-3.15.2/man/nbd-server.5.in.sgml
--- nbd-3.15.1/man/nbd-server.5.in.sgml 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/man/nbd-server.5.in.sgml 2017-02-14 02:13:30.000000000 +0100
@@ -124,6 +124,32 @@
         </listitem>
       </varlistentry>
       <varlistentry>
+       <term><option>cacertfile</option></term>
+       <listitem>
+         <para>
+           Optional; string
+         </para>
+         <para>If this option is set, it should contain a path to
+          a PEM format X.509 CA certificate used for validating client
+          certificates supplied by the client. If this option is not
+          set then client certificates will not be checked.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
+       <term><option>certfile</option></term>
+       <listitem>
+         <para>
+           Optional; string
+         </para>
+         <para>If this option is set, it should contain a path to
+          a PEM format X.509 public certificate used for TLS negotiation
+          with the client. If <option>keyfile</option> is set but
+          <option>certfile</option> is not set, then the server will
+          attempt to read the certificate from the path specified
+          by <option>keyfile</option>.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><option>force_tls</option></term>
         <listitem>
           <para>
@@ -199,6 +225,17 @@
        </listitem>
       </varlistentry>
       <varlistentry>
+       <term><option>keyfile</option></term>
+       <listitem>
+         <para>
+           Optional; string
+         </para>
+         <para>If this option is set, it should contain a path to
+          a PEM format X.509 private key used for TLS negotiation
+          with the client. This option must be set to enable TLS.</para>
+       </listitem>
+      </varlistentry>
+      <varlistentry>
        <term><option>listenaddr</option></term>
        <listitem>
          <para>
@@ -318,43 +355,6 @@
        </listitem>
       </varlistentry>
       <varlistentry>
-       <term><option>keyfile</option></term>
-       <listitem>
-         <para>
-           Optional; string
-         </para>
-         <para>If this option is set, it should contain a path to
-          a PEM format X.509 private key used for TLS negotiation
-          with the client. This option must be set to enable TLS.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><option>certfile</option></term>
-       <listitem>
-         <para>
-           Optional; string
-         </para>
-         <para>If this option is set, it should contain a path to
-          a PEM format X.509 public certificate used for TLS negotiation
-          with the client. If <option>keyfile</option> is set but
-          <option>certfile</option> is not set, then the server will
-          attempt to read the certificate from the path specified
-          by <option>keyfile</option>.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
-       <term><option>cacertfile</option></term>
-       <listitem>
-         <para>
-           Optional; string
-         </para>
-         <para>If this option is set, it should contain a path to
-          a PEM format X.509 CA certificate used for validating client
-          certificates supplied by the client. If this option is not
-          set then client certificates will not be checked.</para>
-       </listitem>
-      </varlistentry>
-      <varlistentry>
         <term><option>tlsonly</option></term>
        <listitem>
          <para>Optional; boolean.</para>
@@ -368,6 +368,28 @@
          </para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><option>tlsprio</option></term>
+       <listitem>
+         <para>Optional; string; default 
NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE</para>
+         <para>This option allows to configure the GnuTLS priority
+           string, which is used to select the algorithms which GnuTLS
+           will allow to be negotiated with the client. The NBD
+           STARTTLS specification requires that clients and servers
+           require TLS1.2 or higher by default, so the default string
+           disables all older versions of the TLS protocol.</para>
+         <para>Not all versions of GnuTLS support the
+           %SERVER_PRECEDENCE flag, which exists to signal that the
+           server should pay no attention to the algorithm preferences
+           selected by the client. If you're using an older version of
+           GnuTLS (e.g., 2.12), it may be necessary to specify a
+           priority string that does not include the %SERVER_PRECEDENCE
+           flag.</para>
+         <para>For an explanation of the possible values of this
+           option, see the "Priority strings" chapter in the GnuTLS
+           documentation.</para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
diff -Nru nbd-3.15.1/man/nbd-server.5.sh.in nbd-3.15.2/man/nbd-server.5.sh.in
--- nbd-3.15.1/man/nbd-server.5.sh.in   2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/man/nbd-server.5.sh.in   2017-02-14 02:15:06.000000000 +0100
@@ -67,6 +67,24 @@
 \fBnbd-client -l\fR to get a list of exports
 on this server.
 .TP
+\fBcacertfile\fR
+Optional; string
+
+If this option is set, it should contain a path to
+a PEM format X.509 CA certificate used for validating client
+certificates supplied by the client. If this option is not
+set then client certificates will not be checked.
+.TP
+\fBcertfile\fR
+Optional; string
+
+If this option is set, it should contain a path to
+a PEM format X.509 public certificate used for TLS negotiation
+with the client. If \fBkeyfile\fR is set but
+\fBcertfile\fR is not set, then the server will
+attempt to read the certificate from the path specified
+by \fBkeyfile\fR\&.
+.TP
 \fBforce_tls\fR
 Optional; boolean.
 
@@ -120,6 +138,13 @@
 whatsoever have been configured, in which case it will
 exit with an appropriate error message)
 .TP
+\fBkeyfile\fR
+Optional; string
+
+If this option is set, it should contain a path to
+a PEM format X.509 private key used for TLS negotiation
+with the client. This option must be set to enable TLS.
+.TP
 \fBlistenaddr\fR
 Optional; string
 
@@ -201,31 +226,6 @@
 with the specified name. Only newstyle negotiation is
 supported on UNIX domain sockets.
 .TP
-\fBkeyfile\fR
-Optional; string
-
-If this option is set, it should contain a path to
-a PEM format X.509 private key used for TLS negotiation
-with the client. This option must be set to enable TLS.
-.TP
-\fBcertfile\fR
-Optional; string
-
-If this option is set, it should contain a path to
-a PEM format X.509 public certificate used for TLS negotiation
-with the client. If \fBkeyfile\fR is set but
-\fBcertfile\fR is not set, then the server will
-attempt to read the certificate from the path specified
-by \fBkeyfile\fR\&.
-.TP
-\fBcacertfile\fR
-Optional; string
-
-If this option is set, it should contain a path to
-a PEM format X.509 CA certificate used for validating client
-certificates supplied by the client. If this option is not
-set then client certificates will not be checked.
-.TP
 \fBtlsonly\fR
 Optional; boolean.
 
@@ -236,6 +236,28 @@
 in the section corresponding to the specific export.
 In order for TLS to work at all, the \fBkeyfile\fR
 option must be specified in the generic section.
+.TP
+\fBtlsprio\fR
+Optional; string; default NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE
+
+This option allows to configure the GnuTLS priority
+string, which is used to select the algorithms which GnuTLS
+will allow to be negotiated with the client. The NBD
+STARTTLS specification requires that clients and servers
+require TLS1.2 or higher by default, so the default string
+disables all older versions of the TLS protocol.
+
+Not all versions of GnuTLS support the
+%SERVER_PRECEDENCE flag, which exists to signal that the
+server should pay no attention to the algorithm preferences
+selected by the client. If you're using an older version of
+GnuTLS (e.g., 2.12), it may be necessary to specify a
+priority string that does not include the %SERVER_PRECEDENCE
+flag.
+
+For an explanation of the possible values of this
+option, see the "Priority strings" chapter in the GnuTLS
+documentation.
 .SH "OPTIONS FOR EXPORT SECTIONS"
 .TP
 \fBauthfile\fR
diff -Nru nbd-3.15.1/nbd-server.c nbd-3.15.2/nbd-server.c
--- nbd-3.15.1/nbd-server.c     2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/nbd-server.c     2017-02-14 02:13:30.000000000 +0100
@@ -262,6 +262,7 @@
        gchar *certfile;        /**< certificate file             */
        gchar *keyfile;         /**< key file                     */
        gchar *cacertfile;      /**< CA certificate file          */
+       gchar *tlsprio;         /**< TLS priority string          */
         gint flags;             /**< global flags                 */
        gint threads;           /**< maximum number of parallel threads we want 
to run */
 };
@@ -778,6 +779,7 @@
                { "certfile",   FALSE, PARAM_STRING,    &(genconftmp.certfile), 
  0 },
                { "keyfile",    FALSE, PARAM_STRING,    &(genconftmp.keyfile),  
  0 },
                { "cacertfile", FALSE, PARAM_STRING,    
&(genconftmp.cacertfile), 0 },
+               { "tlsprio",    FALSE,  PARAM_STRING,   &(genconftmp.tlsprio),  
  0 },
        };
        PARAM* p=gp;
        int p_size=sizeof(gp)/sizeof(PARAM);
@@ -796,6 +798,8 @@
 
         memset(&genconftmp, 0, sizeof(struct generic_conf));
 
+       genconftmp.tlsprio = 
"NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE";
+
         if (genconf) {
                 /* Use the passed configuration values as defaults. The
                  * parsing algorithm below updates all parameter targets
@@ -1626,7 +1630,7 @@
        gnutls_certificate_set_verify_function(x509_cred, verify_cert);
        check_rv(gnutls_certificate_set_x509_trust_file(x509_cred, 
genconf->cacertfile, GNUTLS_X509_FMT_PEM));
        check_rv(gnutls_certificate_set_x509_key_file(x509_cred, 
genconf->certfile, genconf->keyfile, GNUTLS_X509_FMT_PEM));
-       check_rv(gnutls_priority_init(&priority_cache, 
"NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2:%SERVER_PRECEDENCE", NULL));
+       check_rv(gnutls_priority_init(&priority_cache, genconf->tlsprio, NULL));
        check_rv(gnutls_init(session, GNUTLS_SERVER));
        check_rv(gnutls_priority_set(*session, priority_cache));
        check_rv(gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, 
x509_cred));
@@ -3238,6 +3242,7 @@
        dousers(genconf.user, genconf.group);
 
 #if HAVE_GNUTLS
+       gnutls_global_init();
        static gnutls_dh_params_t dh_params;
        gnutls_dh_params_init(&dh_params);
        gnutls_dh_params_generate2(dh_params,
diff -Nru nbd-3.15.1/systemd/.gitignore nbd-3.15.2/systemd/.gitignore
--- nbd-3.15.1/systemd/.gitignore       2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/systemd/.gitignore       1970-01-01 01:00:00.000000000 +0100
@@ -1,3 +0,0 @@
-nbd@.service
-n...@.service.sh
-n...@.service.sh.in
diff -Nru nbd-3.15.1/tests/code/.deps/clientacl.Po 
nbd-3.15.2/tests/code/.deps/clientacl.Po
--- nbd-3.15.1/tests/code/.deps/clientacl.Po    2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/tests/code/.deps/clientacl.Po    1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.deps/dup.Po nbd-3.15.2/tests/code/.deps/dup.Po
--- nbd-3.15.1/tests/code/.deps/dup.Po  2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/code/.deps/dup.Po  1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.deps/mask.Po 
nbd-3.15.2/tests/code/.deps/mask.Po
--- nbd-3.15.1/tests/code/.deps/mask.Po 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/code/.deps/mask.Po 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.deps/punchdummy.Po 
nbd-3.15.2/tests/code/.deps/punchdummy.Po
--- nbd-3.15.1/tests/code/.deps/punchdummy.Po   2016-12-20 20:36:11.000000000 
+0100
+++ nbd-3.15.2/tests/code/.deps/punchdummy.Po   1970-01-01 01:00:00.000000000 
+0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.deps/size.Po 
nbd-3.15.2/tests/code/.deps/size.Po
--- nbd-3.15.1/tests/code/.deps/size.Po 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/code/.deps/size.Po 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.deps/trim.Po 
nbd-3.15.2/tests/code/.deps/trim.Po
--- nbd-3.15.1/tests/code/.deps/trim.Po 2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/code/.deps/trim.Po 1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/code/.gitignore nbd-3.15.2/tests/code/.gitignore
--- nbd-3.15.1/tests/code/.gitignore    2016-11-21 22:43:24.000000000 +0100
+++ nbd-3.15.2/tests/code/.gitignore    1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-clientacl
-dup
-mask
-size
-trim
diff -Nru nbd-3.15.1/tests/run/buffer.c nbd-3.15.2/tests/run/buffer.c
--- nbd-3.15.1/tests/run/buffer.c       1970-01-01 01:00:00.000000000 +0100
+++ nbd-3.15.2/tests/run/buffer.c       2017-01-14 15:47:43.000000000 +0100
@@ -0,0 +1,225 @@
+/*
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Wrymouth Innovation Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include <sys/types.h>
+
+#include "buffer.h"
+
+typedef struct buffer
+{
+  char *buf;
+  ssize_t size;
+  ssize_t hwm;
+  ssize_t ridx;
+  ssize_t widx;
+  int empty;
+} buffer_t;
+
+/* the buffer is organised internally as follows:
+ *
+ * * There are b->size bytes in the buffer.
+ *
+ * * Bytes are at offsets 0 to b->size-1
+ * 
+ * * b->ridx points to the first readable byte
+ *
+ * * b->widx points to the first empty space
+ *
+ * * b->ridx < b->widx indicates a non-wrapped buffer:
+ *
+ *     0       ridx     widx            size
+ *     |       |        |               |
+ *     V       V        V               V
+ *     ........XXXXXXXXX................
+ *
+ * * b->ridx > b->widx indicates a wrapped buffer:
+ *
+ *     0       widx     ridx            size
+ *     |       |        |               |
+ *     V       V        V               V
+ *     XXXXXXXX.........XXXXXXXXXXXXXXXX
+ *
+ * * b->ridx == b->widx indicates a FULL buffer:
+ *
+ * * b->ridx == b->widx indicates a wrapped buffer:
+ *
+ *     0       widx == ridx            size
+ *     |       |                       |
+ *     V       V                       V
+ *     XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+ *
+ * An empty buffer is indicated by empty=1
+ *
+ */
+
+buffer_t *
+bufNew (ssize_t size, ssize_t hwm)
+{
+  buffer_t *b = calloc (1, sizeof (buffer_t));
+  b->buf = calloc (1, size);
+  b->size = size;
+  b->hwm = hwm;
+  b->empty = 1;
+  return b;
+}
+
+
+void
+bufFree (buffer_t * b)
+{
+  free (b->buf);
+  free (b);
+}
+
+/* get a maximal span to read. Returns 0 if buffer
+ * is empty
+ */
+ssize_t
+bufGetReadSpan (buffer_t * b, void **addr)
+{
+  if (b->empty)
+    {
+      *addr = NULL;
+      return 0;
+    }
+  *addr = &(b->buf[b->ridx]);
+  ssize_t len = b->widx - b->ridx;
+  if (len <= 0)
+    len = b->size - b->ridx;
+  return len;
+}
+
+/* get a maximal span to write. Returns 0 id buffer is full
+ */
+ssize_t
+bufGetWriteSpan (buffer_t * b, void **addr)
+{
+  if (b->empty)
+    {
+      *addr = b->buf;
+      b->ridx = 0;
+      b->widx = 0;
+      return b->size;
+    }
+  if (b->ridx == b->widx)
+    {
+      *addr = NULL;
+      return 0;
+    }
+  *addr = &(b->buf[b->widx]);
+  ssize_t len = b->ridx - b->widx;
+  if (len <= 0)
+    len = b->size - b->widx;
+  return len;
+}
+
+/* mark size bytes as read */
+void
+bufDoneRead (buffer_t * b, ssize_t size)
+{
+  while (!b->empty && (size > 0))
+    {
+      /* empty can't occur here, so equal pointers means full */
+      ssize_t len = b->widx - b->ridx;
+      if (len <= 0)
+       len = b->size - b->ridx;
+
+      /* len is the number of bytes in one read span */
+      if (len > size)
+       len = size;
+
+      b->ridx += len;
+      if (b->ridx >= b->size)
+       b->ridx = 0;
+
+      if (b->ridx == b->widx)
+       {
+         b->ridx = 0;
+         b->widx = 0;
+         b->empty = 1;
+       }
+
+      size -= len;
+    }
+}
+
+/* mark size bytes as written */
+void
+bufDoneWrite (buffer_t * b, ssize_t size)
+{
+  while ((b->empty || (b->ridx != b->widx)) && (size > 0))
+    {
+      /* full can't occur here, so equal pointers means empty */
+      ssize_t len = b->ridx - b->widx;
+      if (len <= 0)
+       len = b->size - b->widx;
+
+      /* len is the number of bytes in one write span */
+      if (len > size)
+       len = size;
+
+      b->widx += len;
+      if (b->widx >= b->size)
+       b->widx = 0;
+
+      /* it can't be empty as we've written at least one byte */
+      b->empty = 0;
+
+      size -= len;
+    }
+}
+
+int
+bufIsEmpty (buffer_t * b)
+{
+  return b->empty;
+}
+
+int
+bufIsFull (buffer_t * b)
+{
+  return !b->empty && (b->ridx == b->widx);
+}
+
+int
+bufIsOverHWM (buffer_t * b)
+{
+  return bufGetCount (b) > b->hwm;
+}
+
+ssize_t
+bufGetFree (buffer_t * b)
+{
+  return b->size - bufGetCount (b);
+}
+
+ssize_t
+bufGetCount (buffer_t * b)
+{
+  if (b->empty)
+    return 0;
+  return b->widx - b->ridx + ((b->ridx < b->widx) ? 0 : b->size);
+}
diff -Nru nbd-3.15.1/tests/run/cliserv.c nbd-3.15.2/tests/run/cliserv.c
--- nbd-3.15.1/tests/run/cliserv.c      1970-01-01 01:00:00.000000000 +0100
+++ nbd-3.15.2/tests/run/cliserv.c      2017-01-14 15:47:43.000000000 +0100
@@ -0,0 +1,128 @@
+#include <config.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <cliserv.h>
+#include <nbd-debug.h>
+
+const u64 cliserv_magic = 0x00420281861253LL;
+const u64 opts_magic = 0x49484156454F5054LL;
+const u64 rep_magic = 0x3e889045565a9LL;
+
+/**
+ * Set a socket to blocking or non-blocking
+ *
+ * @param fd The socket's FD
+ * @param nb non-zero to set to non-blocking, else 0 to set to blocking
+ * @return 0 - OK, -1 failed
+ */
+int set_nonblocking(int fd, int nb) {
+       int sf = fcntl (fd, F_GETFL, 0);
+       if (sf == -1)
+               return -1;
+       return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK));
+}
+
+
+void setmysockopt(int sock) {
+       int size = 1;
+#if 0
+       if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(int)) < 0)
+                INFO("(no sockopt/1: %m)");
+#endif
+#ifdef IPPROTO_TCP
+       size = 1;
+       if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &size, sizeof(int)) < 0)
+                INFO("(no sockopt/2: %m)");
+#endif
+#if 0
+       size = 1024;
+       if (setsockopt(sock, IPPROTO_TCP, TCP_MAXSEG, &size, sizeof(int)) < 0)
+                INFO("(no sockopt/3: %m)");
+#endif
+}
+
+void err_nonfatal(const char *s) {
+       char s1[150], *s2;
+
+       strncpy(s1, s, sizeof(s1));
+       if ((s2 = strstr(s, "%m"))) {
+               strcpy(s1 + (s2 - s), strerror(errno));
+               s2 += 2;
+               strcpy(s1 + strlen(s1), s2);
+       }
+#ifndef        sun
+       /* Solaris doesn't have %h in syslog */
+       else if ((s2 = strstr(s, "%h"))) {
+               strcpy(s1 + (s2 - s), hstrerror(h_errno));
+               s2 += 2;
+               strcpy(s1 + strlen(s1), s2);
+       }
+#endif
+
+       s1[sizeof(s1)-1] = '\0';
+#ifdef ISSERVER
+       syslog(LOG_ERR, "%s", s1);
+       syslog(LOG_ERR, "Exiting.");
+#endif
+       fprintf(stderr, "Error: %s\n", s1);
+}
+
+void err(const char *s) {
+       err_nonfatal(s);
+       fprintf(stderr, "Exiting.\n");
+       exit(EXIT_FAILURE);
+}
+
+void logging(const char* name) {
+#ifdef ISSERVER
+       openlog(name, LOG_PID, LOG_DAEMON);
+#endif
+       setvbuf(stdout, NULL, _IONBF, 0);
+       setvbuf(stderr, NULL, _IONBF, 0);
+}
+
+#ifndef ntohll
+#ifdef WORDS_BIGENDIAN
+uint64_t ntohll(uint64_t a) {
+       return a;
+}
+#else
+uint64_t ntohll(uint64_t a) {
+       u32 lo = a & 0xffffffff;
+       u32 hi = a >> 32U;
+       lo = ntohl(lo);
+       hi = ntohl(hi);
+       return ((uint64_t) lo) << 32U | hi;
+}
+#endif
+#endif
+
+/**
+ * Read data from a file descriptor into a buffer
+ *
+ * @param f a file descriptor
+ * @param buf a buffer
+ * @param len the number of bytes to be read
+ **/
+void readit(int f, void *buf, size_t len) {
+       ssize_t res;
+       while (len > 0) {
+               DEBUG("*");
+               res = read(f, buf, len);
+               if (res > 0) {
+                       len -= res;
+                       buf += res;
+               } else if (res < 0) {
+                       if(errno != EAGAIN) {
+                               err("Read failed: %m");
+                       }
+               } else {
+                       err("Read failed: End of file");
+               }
+       }
+}
diff -Nru nbd-3.15.1/tests/run/crypto-gnutls.c 
nbd-3.15.2/tests/run/crypto-gnutls.c
--- nbd-3.15.1/tests/run/crypto-gnutls.c        1970-01-01 01:00:00.000000000 
+0100
+++ nbd-3.15.2/tests/run/crypto-gnutls.c        2017-01-14 15:47:43.000000000 
+0100
@@ -0,0 +1,627 @@
+/*
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Wrymouth Innovation Ltd
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+
+#include "crypto-gnutls.h"
+#include "buffer.h"
+
+#define MAX_CERTS 10
+
+#define FALSE 0
+#define TRUE 1
+
+#define PRIORITY "NORMAL:-VERS-TLS-ALL:+VERS-TLS1.2"
+
+typedef struct tlssession
+{
+  gnutls_certificate_credentials_t creds;
+  gnutls_session_t session;
+  char *hostname;
+  int (*quitfn) (void *opaque);
+  int (*erroutfn) (void *opaque, const char *format, va_list ap);
+  int debug;
+  void *opaque;
+} tlssession_t;
+
+#define BUF_SIZE 65536
+#define BUF_HWM ((BUF_SIZE*3)/4)
+
+static int
+falsequit (void *opaque)
+{
+  return FALSE;
+}
+
+static int
+quit (tlssession_t * s)
+{
+  return s->quitfn (s->opaque);
+}
+
+
+static int
+stderrout (void *opaque, const char *format, va_list ap)
+{
+  return vfprintf (stderr, format, ap);
+}
+
+static int
+errout (tlssession_t * s, const char *format, ...)
+{
+  va_list ap;
+  int ret;
+  va_start (ap, format);
+  ret = s->erroutfn (s->opaque, format, ap);
+  va_end (ap);
+  return ret;
+}
+
+static int
+debugout (tlssession_t * s, const char *format, ...)
+{
+  va_list ap;
+  int ret = 0;
+  va_start (ap, format);
+  if (s->debug)
+    ret = s->erroutfn (s->opaque, format, ap);
+  va_end (ap);
+  return ret;
+}
+
+static int
+socksetnonblock (int fd, int nb)
+{
+  int sf = fcntl (fd, F_GETFL, 0);
+  if (sf == -1)
+    return -1;
+  return fcntl (fd, F_SETFL, nb ? (sf | O_NONBLOCK) : (sf & ~O_NONBLOCK));
+}
+
+/* From (public domain) example file in GNUTLS
+ *
+ * This function will try to verify the peer's certificate, and
+ * also check if the hostname matches, and the activation, expiration dates.
+ */
+static int
+verify_certificate_callback (gnutls_session_t session)
+{
+  unsigned int status;
+  const gnutls_datum_t *cert_list;
+  unsigned int cert_list_size;
+  int ret;
+  gnutls_x509_crt_t cert;
+  tlssession_t *s;
+
+  /* read session pointer */
+  s = (tlssession_t *) gnutls_session_get_ptr (session);
+
+  /* This verification function uses the trusted CAs in the credentials
+   * structure. So you must have installed one or more CA certificates.
+   */
+  ret = gnutls_certificate_verify_peers2 (session, &status);
+  if (ret < 0)
+    {
+      debugout (s, "Could not verfify peer certificate due to an error\n");
+      return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+  if (status & GNUTLS_CERT_INVALID)
+    debugout (s, "The certificate is not trusted.\n");
+
+  if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+    debugout (s, "The certificate hasn't got a known issuer.\n");
+
+  if (status & GNUTLS_CERT_REVOKED)
+    debugout (s, "The certificate has been revoked.\n");
+
+  if (status & GNUTLS_CERT_EXPIRED)
+    debugout (s, "The certificate has expired\n");
+
+  if (status & GNUTLS_CERT_NOT_ACTIVATED)
+    debugout (s, "The certificate is not yet activated\n");
+
+  if (status)
+    return GNUTLS_E_CERTIFICATE_ERROR;
+
+  if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
+    return GNUTLS_E_CERTIFICATE_ERROR;
+
+  if (gnutls_x509_crt_init (&cert) < 0)
+    {
+      debugout (s, "error in initialization\n");
+      return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+  cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
+  if (cert_list == NULL)
+    {
+      debugout (s, "No certificate was found!\n");
+      return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+  /* check only the first certificate - seems to be what curl does */
+  if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
+    {
+      debugout (s, "error parsing certificate\n");
+      return GNUTLS_E_CERTIFICATE_ERROR;
+    }
+
+  if (s->hostname && *s->hostname)
+    {
+      if (!gnutls_x509_crt_check_hostname (cert, s->hostname))
+       {
+         debugout (s,
+                   "The certificate's owner does not match hostname '%s'\n",
+                   s->hostname);
+         return GNUTLS_E_CERTIFICATE_ERROR;
+       }
+    }
+
+  gnutls_x509_crt_deinit (cert);
+
+  debugout (s, "Peer passed certificate verification\n");
+
+  /* notify gnutls to continue handshake normally */
+  return 0;
+}
+
+tlssession_t *
+tlssession_new (int isserver,
+               char *keyfile, char *certfile, char *cacertfile,
+               char *hostname, int insecure, int debug,
+               int (*quitfn) (void *opaque),
+               int (*erroutfn) (void *opaque, const char *format,
+                                va_list ap), void *opaque)
+{
+  int ret;
+  tlssession_t *s = calloc (1, sizeof (tlssession_t));
+
+  if (quitfn)
+    s->quitfn = quitfn;
+  else
+    s->quitfn = falsequit;
+
+  if (erroutfn)
+    s->erroutfn = erroutfn;
+  else
+    s->erroutfn = stderrout;
+
+  if (hostname)
+    s->hostname = strdup (hostname);
+
+  s->debug = debug;
+
+  if (gnutls_certificate_allocate_credentials (&s->creds) < 0)
+    {
+      errout (s, "Certificate allocation memory error\n");
+      goto error;
+    }
+
+  if (cacertfile != NULL)
+    {
+      ret =
+       gnutls_certificate_set_x509_trust_file (s->creds, cacertfile,
+                                               GNUTLS_X509_FMT_PEM);
+      if (ret < 0)
+       {
+         errout (s, "Error setting the x509 trust file: %s\n",
+                 gnutls_strerror (ret));
+         goto error;
+       }
+
+      if (!insecure)
+       {
+         gnutls_certificate_set_verify_function (s->creds,
+                                                 verify_certificate_callback);
+         gnutls_certificate_set_verify_flags (s->creds,
+                                              
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+       }
+    }
+
+  if (keyfile && !certfile)
+    certfile = keyfile;
+
+  if (certfile != NULL && keyfile != NULL)
+    {
+      ret =
+       gnutls_certificate_set_x509_key_file (s->creds, certfile, keyfile,
+                                             GNUTLS_X509_FMT_PEM);
+
+      if (ret < 0)
+       {
+         errout (s,
+                 "Error loading certificate or key file (%s, %s): %s\n",
+                 certfile, keyfile, gnutls_strerror (ret));
+         goto error;
+       }
+    }
+
+  if (isserver)
+    {
+      ret = gnutls_init (&s->session, GNUTLS_SERVER);
+    }
+  else
+    {
+      ret = gnutls_init (&s->session, GNUTLS_CLIENT);
+    }
+  if (ret < 0)
+    {
+      errout (s, "Cannot initialize GNUTLS session: %s\n",
+             gnutls_strerror (ret));
+      goto error;
+    }
+
+  gnutls_session_set_ptr (s->session, (void *) s);
+
+  ret = gnutls_set_default_priority (s->session);
+  if (ret < 0)
+    {
+      errout (s, "Cannot set default GNUTLS session priority: %s\n",
+             gnutls_strerror (ret));
+      goto error;
+    }
+
+  const char *errpos = NULL;
+  ret = gnutls_priority_set_direct (s->session, PRIORITY, &errpos);
+  if (ret < 0)
+    {
+      errout (s, "Cannot set GNUTLS session priority: %s\n",
+             gnutls_strerror (ret));
+      goto error;
+    }
+
+  gnutls_session_set_ptr (s->session, (void *) s);
+
+  ret = gnutls_credentials_set (s->session, GNUTLS_CRD_CERTIFICATE, s->creds);
+  if (ret < 0)
+    {
+      errout (s, "Cannot set session GNUTL credentials: %s\n",
+             gnutls_strerror (ret));
+      goto error;
+    }
+
+  if (isserver)
+    {
+      /* requests but does not check a client certificate */
+      gnutls_certificate_server_set_request (s->session, GNUTLS_CERT_REQUEST);
+    }
+
+
+  return s;
+
+error:
+  if (s->session)
+    gnutls_deinit (s->session);
+  free (s);
+  return NULL;
+}
+
+void
+tlssession_close (tlssession_t * s)
+{
+  if (s->session)
+    gnutls_deinit (s->session);
+  free (s->hostname);
+  free (s);
+}
+
+int
+tlssession_init ()
+{
+  return gnutls_global_init ();
+}
+
+
+int
+tlssession_mainloop (int cryptfd, int plainfd, tlssession_t * s)
+{
+  fd_set readfds;
+  fd_set writefds;
+  int maxfd;
+  int tls_wr_interrupted = 0;
+  int plainEOF = FALSE;
+  int cryptEOF = FALSE;
+  int ret;
+
+  buffer_t *plainToCrypt = bufNew (BUF_SIZE, BUF_HWM);
+  buffer_t *cryptToPlain = bufNew (BUF_SIZE, BUF_HWM);
+
+  if (socksetnonblock (cryptfd, 0) < 0)
+    {
+      errout (s, "Could not turn on blocking: %m");
+      goto error;
+    }
+
+  /* set it up to work with our FD */
+  gnutls_transport_set_ptr (s->session,
+                           (gnutls_transport_ptr_t) (intptr_t) cryptfd);
+
+
+  /* Now do the handshake */
+  ret = gnutls_handshake (s->session);
+  if (ret < 0)
+    {
+      errout (s, "TLS handshake failed: %s\n", gnutls_strerror (ret));
+      goto error;
+    }
+
+  if (socksetnonblock (cryptfd, 1) < 0)
+    {
+      errout (s, "Could not turn on non-blocking on crypt FD: %m");
+      goto error;
+    }
+
+  if (socksetnonblock (plainfd, 1) < 0)
+    {
+      errout (s, "Could not turn on non-blocking on plain FD: %m");
+      goto error;
+    }
+
+  maxfd = (plainfd > cryptfd) ? plainfd + 1 : cryptfd + 1;
+
+  while ((!plainEOF || !cryptEOF) && !quit (s))
+    {
+      struct timeval timeout;
+      int result;
+      int selecterrno;
+      int wait = TRUE;
+
+      FD_ZERO (&readfds);
+      FD_ZERO (&writefds);
+
+      size_t buffered = gnutls_record_check_pending (s->session);
+      if (buffered)
+       wait = FALSE;           /* do not wait for select to return if we have 
buffered data */
+
+      if (plainEOF)
+       {
+         /* plain text end has closed, but me may still have
+          * data yet to write to the crypt end */
+         if (bufIsEmpty (plainToCrypt) && !tls_wr_interrupted)
+           {
+             cryptEOF = TRUE;
+             break;
+           }
+       }
+      else
+       {
+         if (!bufIsEmpty (cryptToPlain))
+           FD_SET (plainfd, &writefds);
+         if (!bufIsOverHWM (plainToCrypt))
+           FD_SET (plainfd, &readfds);
+       }
+
+      if (cryptEOF)
+       {
+         /* crypt end has closed, but me way still have data to
+          * write from the crypt buffer */
+         if (bufIsEmpty (cryptToPlain) && !buffered)
+           {
+             plainEOF = TRUE;
+             break;
+           }
+       }
+      else
+       {
+         if (!bufIsEmpty (plainToCrypt) || tls_wr_interrupted)
+           FD_SET (cryptfd, &writefds);
+         if (!bufIsOverHWM (cryptToPlain))
+           FD_SET (cryptfd, &readfds);
+       }
+
+      /* Repeat select whilst EINTR happens */
+      do
+       {
+         timeout.tv_sec = wait ? 1 : 0;
+         timeout.tv_usec = 0;
+         result = select (maxfd, &readfds, &writefds, NULL, &timeout);
+
+         selecterrno = errno;
+       }
+      while ((result == -1) && (selecterrno == EINTR) && !quit (s));
+      if (quit (s))
+       break;
+
+      if (FD_ISSET (plainfd, &readfds))
+       {
+         /* we can read at least one byte */
+         void *addr = NULL;
+         /* get a span of characters to write to the
+          * buffer. As the empty portion may wrap the end of the
+          * circular buffer this might not be all we could read.
+          */
+         ssize_t len = bufGetWriteSpan (plainToCrypt, &addr);
+         if (len > 0)
+           {
+             ssize_t ret;
+             do
+               {
+                 ret = read (plainfd, addr, (size_t) len);
+               }
+             while ((ret < 0) && (errno == EINTR) && !quit (s));
+             if (quit (s))
+               break;
+             if (ret < 0)
+               {
+                 errout (s, "Error on read from plain socket: %m\n");
+                 goto error;
+               }
+             if (ret == 0)
+               {
+                 plainEOF = TRUE;
+               }
+             else
+               {
+                 bufDoneWrite (plainToCrypt, ret);     /* mark ret bytes as 
written to the buffer */
+               }
+           }
+       }
+
+      if (FD_ISSET (plainfd, &writefds))
+       {
+         /* we can write at least one byte */
+         void *addr = NULL;
+         /* get a span of characters to read from the buffer
+          * as the full portion may wrap the end of the circular buffer
+          * this might not be all we have to write.
+          */
+         ssize_t len = bufGetReadSpan (cryptToPlain, &addr);
+         if (len > 0)
+           {
+             ssize_t ret;
+             do
+               {
+                 ret = write (plainfd, addr, (size_t) len);
+               }
+             while ((ret < 0) && (errno == EINTR) && !quit (s));
+             if (quit (s))
+               break;
+             if (ret < 0)
+               {
+                 errout (s, "Error on write to plain socket: %m\n");
+                 goto error;
+               }
+             bufDoneRead (cryptToPlain, ret);  /* mark ret bytes as read from 
the buffer */
+           }
+       }
+
+      if (FD_ISSET (cryptfd, &readfds) || buffered)
+       {
+         /* we can read at least one byte */
+         void *addr = NULL;
+         /* get a span of characters to write to the
+          * buffer. As the empty portion may wrap the end of the
+          * circular buffer this might not be all we could read.
+          */
+         ssize_t len = bufGetWriteSpan (cryptToPlain, &addr);
+         if (len > 0)
+           {
+             ssize_t ret;
+             do
+               {
+                 ret = gnutls_record_recv (s->session, addr, (size_t) len);
+               }
+             while (ret == GNUTLS_E_INTERRUPTED && !quit (s));
+             /* do not loop on GNUTLS_E_AGAIN - this means we'd block so we'd 
loop for
+              * ever
+              */
+             if (quit (s))
+               break;
+             if (ret < 0 && ret != GNUTLS_E_AGAIN)
+               {
+                 errout (s, "Error on read from crypt socket: %s\n",
+                         gnutls_strerror (ret));
+                 goto error;
+               }
+             if (ret == 0)
+               {
+                 cryptEOF = TRUE;
+               }
+             else
+               {
+                 bufDoneWrite (cryptToPlain, ret);     /* mark ret bytes as 
written to the buffer */
+               }
+           }
+       }
+
+      if (FD_ISSET (cryptfd, &writefds))
+       {
+         /* we can write at least one byte */
+         void *addr = NULL;
+         /* get a span of characters to read from the buffer
+          * as the full portion may wrap the end of the circular buffer
+          * this might not be all we have to write.
+          */
+         ssize_t len = bufGetReadSpan (plainToCrypt, &addr);
+         if (len > 0)
+           {
+             ssize_t ret;
+             do
+               {
+                 if (tls_wr_interrupted)
+                   {
+                     ret = gnutls_record_send (s->session, NULL, 0);
+                   }
+                 else
+                   {
+                     ret = gnutls_record_send (s->session, addr, len);
+                   }
+               }
+             while (ret == GNUTLS_E_INTERRUPTED && !quit (s));
+             if (quit (s))
+               break;
+             if (ret == GNUTLS_E_AGAIN)
+               {
+                 /* we need to call this again with NULL parameters
+                  * as it blocked
+                  */
+                 tls_wr_interrupted = TRUE;
+               }
+             else if (ret < 0)
+               {
+                 errout (s, "Error on write to crypto socket: %s\n",
+                         gnutls_strerror (ret));
+                 goto error;
+               }
+             else
+               {
+                 bufDoneRead (plainToCrypt, ret);      /* mark ret bytes as 
read from the buffer */
+               }
+           }
+       }
+    }
+
+  ret = 0;
+  goto freereturn;
+
+error:
+  ret = -1;
+
+freereturn:
+  gnutls_bye (s->session, GNUTLS_SHUT_RDWR);
+  shutdown (plainfd, SHUT_RDWR);
+  bufFree (plainToCrypt);
+  bufFree (cryptToPlain);
+  return ret;
+}
diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-buffer.Po 
nbd-3.15.2/tests/run/.deps/nbd_tester_client-buffer.Po
--- nbd-3.15.1/tests/run/.deps/nbd_tester_client-buffer.Po      2016-12-20 
20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-buffer.Po      1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-cliserv.Po 
nbd-3.15.2/tests/run/.deps/nbd_tester_client-cliserv.Po
--- nbd-3.15.1/tests/run/.deps/nbd_tester_client-cliserv.Po     2016-12-20 
20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-cliserv.Po     1970-01-01 
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po 
nbd-3.15.2/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po
--- nbd-3.15.1/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po       
2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-crypto-gnutls.Po       
1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy
diff -Nru nbd-3.15.1/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po 
nbd-3.15.2/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po
--- nbd-3.15.1/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po   
2016-12-20 20:36:11.000000000 +0100
+++ nbd-3.15.2/tests/run/.deps/nbd_tester_client-nbd-tester-client.Po   
1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-# dummy

Reply via email to