Blob Blame History Raw
diff -urN parallel-3.1.3/doc/parallel.txi octave-parallel/doc/parallel.txi
--- parallel-3.1.3/doc/parallel.txi	2018-08-03 09:41:42.526477339 +0200
+++ octave-parallel/doc/parallel.txi	2019-08-02 12:43:39.610208685 +0200
@@ -260,8 +260,9 @@
 @section Starting servers
 @mfnindex pserver
 
-@c include function helptext here
-@DOCSTRING(pserver)
+@anchor{XREFpserver}
+This section is currently invalid. (This is a development version of the
+parallel package.)
 
 @c ------------------------------------------------------------------
 
diff -urN parallel-3.1.3/src/common.h octave-parallel/src/common.h
--- parallel-3.1.3/src/common.h	1970-01-01 01:00:00.000000000 +0100
+++ octave-parallel/src/common.h	2019-08-02 12:43:39.644208069 +0200
@@ -0,0 +1,6 @@
+// This file is in the public domain.
+
+// these ports were originally used by pserver
+// ports 12346--12752 are unassigned by IANA as of 2019-04-20
+#define DEFAULT_CMD_PORT "12502"
+#define DEFAULT_DATA_PORT "12501"
diff -urN parallel-3.1.3/src/configure.ac octave-parallel/src/configure.ac
--- parallel-3.1.3/src/configure.ac	2018-08-03 09:41:42.534477496 +0200
+++ octave-parallel/src/configure.ac	2019-08-02 12:43:39.645208051 +0200
@@ -272,7 +272,7 @@
 [dnl
   [oct_mach_info],
   [octave::mach_info],
-  [[std::cout << octave::mach_info::flt_fmt_unknown;]],
+  [[int f = octave::mach_info::flt_fmt_unknown;]],
   [OCTAVE__MACH_INFO],
   [],
   []
@@ -378,15 +378,6 @@
 ],
 
 [dnl
-  [eval_string],
-  [octave::eval_string],
-  [[int p_err; octave::eval_string ("date", false, p_err, 0);]],
-  [OCTAVE__EVAL_STRING],
-  [[#include <octave/parse.h>]],
-  [[#include <octave/parse.h>]]
-],
-
-[dnl
   [file_stat],
   [octave::sys::file_stat],
   [[octave::sys::file_stat ();]],
@@ -402,6 +393,35 @@
   [ADD_OCTAVE__INTERPRETER__CALL_STACK__POP],
   [],
   []
+],
+
+[dnl
+  [octave_vformat],
+  [octave::vformat],
+  [[std::ostringstream obuf;]
+   [va_list args;]
+   [octave::vformat (obuf, "dummy", args);]],
+  [OCTAVE__VFORMAT],
+  [],
+  []
+],
+
+[dnl
+  [command_editor],
+  [octave::command_editor],
+  [[octave::command_editor::increment_current_command_number ();]],
+  [OCTAVE__COMMAND_EDITOR],
+  [[#include <octave/cmd-edit.h>]],
+  [[#include <octave/cmd-edit.h>]]
+],
+
+[dnl
+  [octave_env],
+  [octave::sys::env],
+  [[octave::sys::env::get_current_directory ();]],
+  [OCTAVE__SYS__ENV],
+  [[#include <octave/oct-env.h>]],
+  [[#include <octave/oct-env.h>]]
 ]
 
 ],
@@ -419,6 +439,27 @@
     [AC_MSG_RESULT([no])]
   )
 
+AC_MSG_CHECKING([for eval_string])
+  AC_COMPILE_IFELSE(
+    [AC_LANG_PROGRAM([[#include <octave/oct.h>]],
+                     [std::string cmd ("date"); int p_err; octave::interpreter::the_interpreter () -> eval_string (cmd, false, p_err, 0);])],
+    [AC_DEFINE([OCTAVE__EVAL_STRING], [octave::interpreter::the_interpreter () -> eval_string],
+               [macro for alternatives to octave::eval_string])
+     AC_MSG_RESULT([octave::interpreter::eval_string])],
+    [AC_COMPILE_IFELSE(
+      [AC_LANG_PROGRAM([[#include <octave/oct.h>]
+                        [#include <octave/parse.h>]],
+                       [int p_err; octave::eval_string ("date", false, p_err, 0);])],
+      [AC_DEFINE([OCTAVE__EVAL_STRING], [octave::eval_string],
+                 [macro for alternatives to octave::eval_string])
+       AC_MSG_RESULT([octave::eval_string])
+       echo '#include <octave/parse.h>' >> oct-alt-includes.h],
+      [AC_DEFINE([OCTAVE__EVAL_STRING], [eval_string],
+                 [macro for alternatives to octave::eval_string])
+       AC_MSG_RESULT([eval_string])
+       echo '#include <octave/parse.h>' >> oct-alt-includes.h])]
+)
+
 LIBS=$TLIBS
 LDFLAGS=$TLDFLAGS
 CXXFLAGS=$TCXXFLAGS
@@ -429,4 +470,6 @@
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
 
-AH_BOTTOM([#include "custom.h"])
+AH_BOTTOM([#ifndef EXTERNAL_BINARY
+#include "custom.h"
+#endif])
diff -urN parallel-3.1.3/src/error-helpers.cc octave-parallel/src/error-helpers.cc
--- parallel-3.1.3/src/error-helpers.cc	2018-08-03 09:41:42.534477496 +0200
+++ octave-parallel/src/error-helpers.cc	2019-08-02 12:43:39.645208051 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
@@ -50,7 +50,7 @@
 
   std::ostringstream output_buf;
 
-  octave_vformat (output_buf, fmt, args);
+  OCTAVE__VFORMAT (output_buf, fmt, args);
 
   std::string msg = output_buf.str ();
 
diff -urN parallel-3.1.3/src/error-helpers.h octave-parallel/src/error-helpers.h
--- parallel-3.1.3/src/error-helpers.h	2018-08-03 09:41:42.534477496 +0200
+++ octave-parallel/src/error-helpers.h	2019-08-02 12:43:39.646208032 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
@@ -19,6 +19,8 @@
 
 #include "config.h"
 
+#include <iostream>
+
 // Octaves non-static verror functions: The elder all set error_state,
 // the newer, present from the time on at which error started to throw
 // an exception, all throw, too.
diff -urN parallel-3.1.3/src/fload.cc octave-parallel/src/fload.cc
--- parallel-3.1.3/src/fload.cc	2018-08-03 09:41:42.538477575 +0200
+++ octave-parallel/src/fload.cc	2019-08-02 12:43:39.646208032 +0200
@@ -29,7 +29,6 @@
 @deftypefn {Loadable Function} {@var{var} =} fload (@var{fid})\n\
 Loads a single variable of any type from a binary stream, where it was previously\n\
 saved with fsave.\n\
-Not suitable for data transfer between machines of different type.\n\
 @end deftypefn")
 {
   octave_value retval;
@@ -48,6 +47,10 @@
           bool swap;
           OCTAVE__MACH_INFO::float_format flt_fmt;
 
+          // This wouldn't be necessary within the local machine, but
+          // fload may be used outside parcellfun and the current
+          // version of parcellfun will become deprecated anyway since
+          // it forkes Octave.
           if (minimal_read_header (*is, swap, flt_fmt))
             {
               error ("fload: could not read binary header");
diff -urN parallel-3.1.3/src/fsave.cc octave-parallel/src/fsave.cc
--- parallel-3.1.3/src/fsave.cc	2018-08-03 09:41:42.538477575 +0200
+++ octave-parallel/src/fsave.cc	2019-08-02 12:43:39.647208014 +0200
@@ -28,8 +28,7 @@
   "-*- texinfo -*-\n\
 @deftypefn {Loadable Function} {} fsave (@var{fid}, @var{var})\n\
 Save a single variable to a binary stream, to be subsequently loaded with\n\
-fload. Returns true if successful.\n\
-Not suitable for data transfer between machines of different type.\n\
+fload.\n\
 @end deftypefn")
 {
   octave_value retval;
@@ -47,6 +46,10 @@
 
       if (os)
         {
+          // This wouldn't be necessary within the local machine, but
+          // fsave may be used outside parcellfun and the current
+          // version of parcellfun will become deprecated anyway since
+          // it forkes Octave.
           minimal_write_header (*os);
 
           if (minimal_write_data (*os, val))
diff -urN parallel-3.1.3/src/getpass.c octave-parallel/src/getpass.c
--- parallel-3.1.3/src/getpass.c	2018-08-03 09:41:42.538477575 +0200
+++ octave-parallel/src/getpass.c	2019-08-02 12:43:39.647208014 +0200
@@ -4,7 +4,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/m4/octave-forge.m4 octave-parallel/src/m4/octave-forge.m4
--- parallel-3.1.3/src/m4/octave-forge.m4	2018-08-03 09:41:42.554477891 +0200
+++ octave-parallel/src/m4/octave-forge.m4	2019-08-02 12:43:39.648207996 +0200
@@ -88,6 +88,8 @@
 
 m4_foreach([it], [$1], [m4_apply([OF_OCTAVE_ALT_SYMS], [it, $2])])
 
-AH_BOTTOM([#include "$2"])
+AH_BOTTOM([#ifndef EXTERNAL_BINARY
+#include "$2"
+#endif])
 
 ])
diff -urN parallel-3.1.3/src/Makefile.in octave-parallel/src/Makefile.in
--- parallel-3.1.3/src/Makefile.in	2018-08-03 09:41:42.534477496 +0200
+++ octave-parallel/src/Makefile.in	2019-08-02 12:43:39.641208123 +0200
@@ -66,9 +66,14 @@
        netcellfun.m __pserver_exit__.m rfeval.m scloseall.m server.m
 endif
 
+# the server is a standalone binary
+standalone := octave-pserver
+
 # All compiled user functions for parallel cluster must be in one
 # file, otherwise registration of new octave_base_value derived type
-# is not seen by the other functions.
+# is not seen by the other functions. Even the server function must be
+# included, since the server, too, will usually run some other user
+# functions which accept a parallel connections object.
 cluster_oct := parallel_interface.oct
 
 local_octs_set1 := fload.oct fsave.oct __exit__.oct
@@ -79,9 +84,11 @@
 
 cluster_objs = $(cluster_oobjs) $(cluster_lobjs)
 
-t_cluster_oobjs := pconnect.o pserver.o sclose.o \
-                   reval.o precv.o psend.o select_sockets.o \
-                   network_get_info.o network_set.o
+cluster_user_oobjs := pconnect.o sclose.o \
+                      reval.o precv.o psend.o select_sockets.o \
+                      network_get_info.o network_set.o
+
+t_cluster_oobjs := $(cluster_user_oobjs) __octave_server__.o
 
 cluster_lobjs := p-connection.o p-streams.o
 
@@ -114,7 +121,7 @@
 TXIFILE := $(addsuffix .txi,$(basename $(INFOFILE)))
 HTMLDIR := ../doc/html/
 
-DEFUNDLDFILES := $(addsuffix .cc,$(basename $(t_cluster_oobjs))) \
+DEFUNDLDFILES := $(addsuffix .cc,$(basename $(cluster_user_oobjs))) \
                  $(generate_srp_data_source) \
                  $(addsuffix .cc,$(basename $(local_octs)))
 
@@ -126,7 +133,7 @@
 
 .INTERMEDIATE: MFDOCSTRINGS $(DSFILES)
 
-all: doc $(octs) $(ms)
+all: doc $(octs) $(ms) $(standalone)
 
 prebuild: doc html
 
@@ -141,8 +148,11 @@
 
 $(octs): error-helpers.h minimal-load-save.h
 
-$(cluster_objs): parallel-gnutls.h p-connection.h p-streams.h sensitive-data.h \
-                 p-sighandler.h
+$(cluster_objs): parallel-gnutls.h parallel-gnutls-nonoctave.h \
+                 p-connection.h p-streams.h \
+                 sensitive-data.h p-sighandler.h
+
+$(standalone): parallel-gnutls-nonoctave.h common.h
 
 # CXX default is set by configure to the default used by mkoctfile,
 # possibly enhanced with an option to enforce C++11 features.
@@ -165,6 +175,10 @@
 $(ms): %.m: %.copy_to_m
 	cp $< $(addsuffix .m,$(basename $<))
 
+$(standalone): octave-pserver.cc octave-pserver.h
+	$(CXX) -pthread -Wall -o octave-pserver octave-pserver.cc
+	install -D octave-pserver ../bin/octave-pserver
+
 doc: $(INFOFILE)
 
 $(INFOFILE): $(TEXIFILE)
@@ -206,10 +220,10 @@
 	(echo "#include <stdio.h>"; echo "int main () {"; sed -e s/DEFUN_DLD/$(RDEFUN_DLD)/g -e s/DEFUNX_DLD/$(RDEFUNX_DLD)/g $< | $(CXXCPP) `$(MKOCTFILE) -p INCFLAGS` -x c++ -iquote '.' -D'$(RDEFUN_DLD)(name,args,nargout,doc)=$(RDEFUN_DLD)(name,doc)' -D'$(RDEFUNX_DLD)(name,fname,gname,args,nargout,doc)=$(RDEFUN_DLD)(name,doc)' - | sed -e '/.*$(RDEFUN_DLD)/!D'; echo "}";) | $(CXX) -x c++ -D'$(RDEFUN_DLD)(name,doc)=printf("%c" #name "\n@c " #name " $<\n" doc "\n\n", 0x1D);' -o $@ -
 
 clean:
-	$(RM) *.o *.oct *.m octave-core *.cc.docstrings MFDOCSTRINGS *~
+	$(RM) $(standalone) *.o *.oct *.m octave-core *.cc.docstrings MFDOCSTRINGS *~
 
-distclean:
-	$(RM) *.o *.oct *.m octave-core *.cc.docstrings config.h config.log config.status MFDOCSTRINGS *~
+distclean: clean
+	$(RM) config.h config.log config.status
 
-maintainer-clean:
-	$(RM) *.o *.oct *.m octave-core *.cc.docstrings config.h config.log config.status MFDOCSTRINGS *~ $(INFOFILE) $(TEXIFILE)
+maintainer-clean: distclean
+	$(RM) $(INFOFILE) $(TEXIFILE)
diff -urN parallel-3.1.3/src/network_get_info.cc octave-parallel/src/network_get_info.cc
--- parallel-3.1.3/src/network_get_info.cc	2018-08-03 09:41:42.566478128 +0200
+++ octave-parallel/src/network_get_info.cc	2019-08-02 12:43:39.651207942 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/network_set.cc octave-parallel/src/network_set.cc
--- parallel-3.1.3/src/network_set.cc	2018-08-03 09:41:42.566478128 +0200
+++ octave-parallel/src/network_set.cc	2019-08-02 12:43:39.651207942 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/oct-alt-includes.h octave-parallel/src/oct-alt-includes.h
--- parallel-3.1.3/src/oct-alt-includes.h	2018-08-03 09:43:47.096936914 +0200
+++ octave-parallel/src/oct-alt-includes.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,44 +0,0 @@
-/* generated by configure */
-
-
-#include <octave/file-ops.h>
-
-
-
-
-
-
-
-
-
-#include <octave/oct-stream.h>
-
-#include <octave/oct-stream.h>
-
-#include <octave/sighandlers.h>
-
-
-
-
-
-
-
-
-
-
-
-#include <octave/oct-stream.h>
-
-#include <octave/oct-refcount.h>
-
-#include <octave/parse.h>
-
-#include <octave/parse.h>
-
-#include <octave/file-stat.h>
-
-
-
-
-
-#include <octave/defaults.h>
diff -urN parallel-3.1.3/src/octave-pserver.cc octave-parallel/src/octave-pserver.cc
--- parallel-3.1.3/src/octave-pserver.cc	1970-01-01 01:00:00.000000000 +0100
+++ octave-parallel/src/octave-pserver.cc	2019-08-02 12:43:39.651207942 +0200
@@ -0,0 +1,679 @@
+/*
+
+Copyright (C) 2002 Hayato Fujiwara <h_fujiwara@users.sourceforge.net>
+Copyright (C) 2010-2018 Olaf Till <i7tiol@t-online.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#define EXTERNAL_BINARY
+#include "config.h"
+
+#include <stdio.h>
+#include <error.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/utsname.h>
+#include <netinet/in.h> // reported necessary for FreeBSD-8
+#include <signal.h>
+#include <string.h>
+#include <pthread.h>
+#include <sstream>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "parallel-gnutls-nonoctave.h"
+#include "octave-pserver.h"
+
+struct option p_cmdline_options::known_long_opts[N_LONGOPTS + 1] =
+  {
+    {
+      .name    = "use-tls",
+      .has_arg = 0, // 0: has no argument
+      .flag    = NULL,
+      .val     = 1
+    },
+
+    {
+      .name    = "no-auth",
+      .has_arg = 0, // 0: has no argument
+      .flag    = NULL,
+      .val     = 2
+    },
+
+    {
+      .name    = "auth-file",
+      .has_arg = 1, // 1: requires an argument
+      .flag    = NULL,
+      .val     = 3
+    },
+
+    {
+      .name    = "octave-binary",
+      .has_arg = 1, // 1: requires an argument
+      .flag    = NULL,
+      .val     = 4
+    },
+
+    {
+      .name    = "cmd-port",
+      .has_arg = 1, // 1: requires an argument
+      .flag    = NULL,
+      .val     = 5
+    },
+    
+    {
+      .name    = "data-port",
+      .has_arg = 1, // 1: requires an argument
+      .flag    = NULL,
+      .val     = 6
+    },
+
+    {
+      .name    = "help",
+      .has_arg = 0, // 0: has no argument
+      .flag    = NULL,
+      .val     = 7
+    },
+
+    // end marker, must be filled with zeros
+    {
+      .name    = NULL,
+      .has_arg = 0,
+      .flag    = NULL,
+      .val     = 0
+    }
+  }; // remember to adjust N_LONGOPTS when adding options
+
+p_cmdline_options::p_cmdline_options (int argc, char * const *argv)
+  : opt_use_tls (true), opt_print_help (false),
+    opt_cmd_port_string (DEFAULT_CMD_PORT),
+    opt_data_port_string (DEFAULT_DATA_PORT)
+{
+  extern char *optarg; // provided by glibc for getopt and related functions
+
+  opt_cmd_port = atoi (DEFAULT_CMD_PORT);
+  opt_data_port = atoi (DEFAULT_DATA_PORT);
+
+  for (;;)
+    {
+      int opt = getopt_long (argc, argv, "h", known_long_opts, NULL);
+
+      if (opt == -1)
+        break;
+
+      switch (opt)
+        {
+        case '?':
+          // getopt_long has already printed an error message
+          exit (1);
+          break;
+        case 1:
+          opt_use_tls = true;
+          break;
+        case 2:
+          opt_use_tls = false;
+          break;
+        case 3:
+          opt_auth_file = optarg;
+          break;
+        case 4:
+          opt_octave_binary = optarg;
+          break;
+        case 5:
+          opt_cmd_port = atoi (optarg);
+          opt_cmd_port_string = optarg;
+          break;
+        case 6:
+          opt_data_port = atoi (optarg);
+          opt_data_port_string = optarg;
+          break;
+        case 'h':
+        case 7:
+          opt_print_help = true;
+          break;
+        default:
+          error (0, 0, "internal error, unhandled known option");
+          exit (1);
+          break;
+        }
+    }
+}
+
+static int check_and_write_pidfile (const char *fname, int pid)
+{
+  int fd, ret, nread;
+
+  while ((fd = open (fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0 &&
+         errno == EINTR);
+  if (fd < 0)
+    return -1;
+
+  struct flock fl;
+  fl.l_type = F_WRLCK;
+  fl.l_whence = SEEK_SET;
+  fl.l_start = 0;
+  fl.l_len = 0;
+  while ((ret = fcntl (fd, F_SETLKW, &fl)) < 0 && errno == EINTR);
+  if (ret < 0)
+    {
+      close (fd);
+      return -1;
+    }
+
+  char b;
+  while ((nread = read (fd, &b, 1)) < 0 && errno == EINTR);
+  if (nread < 0 || nread == 1)
+    {
+      close (fd);
+      return -1;
+    }
+
+  if (lseek (fd, 0, SEEK_SET))
+    {
+      close (fd);
+      return -1;
+    }
+
+  FILE *fstr;
+  if (! (fstr = fdopen (fd, "w+")))
+    {
+      close (fd);
+      return -1;
+    }
+
+  if (fprintf (fstr, "%i", pid) < 0)
+    {
+      fclose (fstr);
+      return -1;
+    }
+
+  if (fclose (fstr) == EOF)
+    return -1;
+  else
+    return 0;
+}
+
+static
+const std::string &stash_or_get_hostname (std::string hn)
+{
+  static std::string stored_hostname;
+  static std::string empty_string;
+
+  if (hn.length ())
+    {
+      stored_hostname = hn;
+
+      return empty_string;
+    }
+
+  return stored_hostname;
+}
+
+void print_hostname_atexit (void)
+{
+  printf ("exiting, %s\n", stash_or_get_hostname (std::string ()).c_str ());
+}
+
+static
+const std::string& stash_or_get_pidfile (std::string path)
+{
+  static std::string stored_pidfile;
+  static std::string empty_string;
+
+  if (path.length ())
+    {
+      stored_pidfile = path;
+
+      return empty_string;
+    }
+
+  return stored_pidfile;
+}
+
+void unlink_pidfile_atexit (void)
+{
+  unlink (stash_or_get_pidfile (std::string ()).c_str ());
+}
+
+void * pull_signals (void *arg)
+{
+  pthread_t parent_thread = *((pthread_t *) arg);
+
+  int sig = 0;
+
+  sigset_t allsigs;
+
+  if (! sigfillset (&allsigs))
+    while (! (sigwait (&allsigs, &sig)
+              || sig == SIGTERM
+              || sig == SIGHUP));
+
+  pthread_cancel (parent_thread);
+
+  if (pthread_join (parent_thread, NULL))
+    {
+      // this should not happen and may not exit cleanly
+      error (0, 0, "couldn't join parent thread, emergency exit");
+      exit (1);
+    }
+
+  pthread_exit (0);
+}
+
+static
+void check_options (p_cmdline_options &opts, int &oct_fd)
+{
+  if (opts.print_help ())
+    {
+      std::cout << "octave-pserver is an executable distruted with the package 'parallel'," << std::endl
+                << "version " << "..." << ", for GNU/Octave." << std::endl
+                << "Copyright (C) 2002 Hayato Fujiwara." << std::endl
+                << "Copyright (C) 2010-2019 Olaf Till." << std::endl
+                << "This is free software; see the source code for copying conditions." << std::endl
+                << "There is ABSOLUTLY NO WARRANTY; not even for MERCHANTABILITY or" << std::endl 
+                << "FITNESS FOR A PARTICULAR PURPOSE." << std::endl
+                << std::endl
+                << "Usage:" << std::endl
+                << "See documentation of package 'parallel'." << std::endl
+                << "call indirectly from Octave with 'pserver (...)'" << std::endl
+                << "or call it directly: octave-pserver --octave-binary <octave binary> [further options]" << std::endl
+                << std::endl
+                << "Options:" << std::endl
+                << std::endl
+                << "-h/--help       : prints this helptext" << std::endl
+                << "--octave-binary : absolute path to octave binary" << std::endl
+                << "--use-tls       : use TLS (default) for authentication and ecryption" << std::endl
+                << "--no-auth       : no authentication or encryption" << std::endl
+                << "--auth-file     : path to authentication file" << std::endl
+                << "--cmd-port      : port for command channel, default "
+                << DEFAULT_CMD_PORT << std::endl
+                << "--data-port     : port for data channel, default "
+                << DEFAULT_DATA_PORT << std::endl;
+      exit (0);
+    }
+  if (opts.octave_binary ().size () < 2
+      || opts.octave_binary ()[0] != '/')
+    {
+      error (0, 0, "octave_binary must be given and must be an absolute filename");
+      exit (1);
+    }
+  // open the binary to avoid racing conditions
+  oct_fd = open (opts.octave_binary ().c_str (), O_RDONLY | O_CLOEXEC);
+  if (oct_fd == -1)
+    {
+      perror ("open");
+      exit (1);
+    }
+  struct stat statbuf;
+  if (fstat (oct_fd, &statbuf))
+    {
+      perror ("fstat");
+      exit (1);
+    }
+  if (! S_ISREG (statbuf.st_mode))
+    {
+      error (0, 0, "octave_binary is no regular file");
+      exit (1);
+    }
+  if (! (statbuf.st_mode & S_IXUSR))
+    {
+      error (0, 0, "octave_binary is not executable");
+      exit (1);
+    }
+  if (statbuf.st_mode & S_ISUID)
+    {
+      error (0, 0, "octave_binary must not have the set-user-ID bit set");
+      exit (1);
+    }
+  if (opts.cmd_port () < 1024 || opts.cmd_port () > 65535)
+    {
+      error (0, 0, "cmd_port must be >= 1024 and <= 65535");
+      exit (1);
+    }
+  if (opts.data_port () < 1024 || opts.data_port () > 65535)
+    {
+      error (0, 0, "data_port must be >= 1024 and <= 65535");
+      exit (1);
+    }
+  if (opts.cmd_port () == opts.data_port ())
+    {
+      error (0, 0, "cmd_port and data_port must not be equal");
+      exit (1);
+    }
+#ifndef HAVE_LIBGNUTLS
+  if (opts.use_tls ())
+    {
+      error (0, 0, "TLS not available");
+      exit (1);
+    }
+#endif
+  if (! opts.use_tls () && opts.auth_file ().length ())
+    error (0, 0, "no TLS used, option 'auth_file' has no effect");
+}
+
+// For execv, we need to copy some const char* to non-const. We can
+// use new without delete since this function is only called between
+// fork() and exec().
+static
+char * copy_to_non_const (const char *str)
+{
+  char *ret = new char [strlen (str)];
+
+  strcpy (ret, str);
+
+  return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+  std::string fname ("octave-pserver");
+
+  // don't run as root and try not to run with elevated privileges
+  uid_t uid = getuid (), euid = geteuid ();
+  if (uid == 0)
+    {
+      error (0, 0, "running this program as root is regarded as dangerous, aborting");
+      exit (1);
+    }
+  if (uid < 0 || uid != euid)
+    {
+      error (0, 0, "The program seems to be run with elevated privileges. This is regarded as dangerous, aborting.");
+      exit (1);
+    }
+
+  p_cmdline_options opts (argc, argv);
+
+  int oct_fd; // octave_binary will be opened by check_options() to
+              // avoid racing conditions
+  check_options (opts, oct_fd);
+
+  struct utsname utsname_buf;
+  if (uname (&utsname_buf))
+    {
+      perror ("uname");
+      exit (1);
+    }
+  std::string hostname (utsname_buf.nodename);
+  std::string pidname ("/tmp/.octave-");
+  pidname = pidname + hostname + ".pid";
+
+  // initialize atexit function to write "exiting, hostname\n"
+  stash_or_get_hostname (hostname);
+
+  int tp;
+  if ((tp = fork ()))
+    {
+      if (tp == -1)
+        {
+          error (0, 0, "could not fork");
+          exit (1);
+        }
+
+      exit (0);
+    }
+
+  // register atexit function to write "exiting, hostname\n"
+  if (atexit (print_hostname_atexit))
+    {
+      perror ("atexit");
+      exit (1);
+    }
+
+  // block signals
+  sigset_t blockedsigs;
+  if (sigfillset (&blockedsigs)
+      || pthread_sigmask (SIG_BLOCK, &blockedsigs, NULL))
+    {
+      error (0, 0, "could not block signals");
+      exit (1);
+    }
+
+  /* write pidfile */
+  if (check_and_write_pidfile (pidname.c_str (), getpid ()))
+    {
+      std::cerr << "octave-pserver: " << hostname.c_str ()
+                << ": can't write pidfile, server possibly already running"
+                << std::endl;
+      exit (1);
+    }
+
+  // register atexit function which unlinks pidfile
+  stash_or_get_pidfile (pidname);
+  if (atexit (unlink_pidfile_atexit))
+    {
+      perror ("atexit");
+      exit (1);
+    }
+
+  // install signal handling pthread which exits the whole process at
+  // termination signals
+  pthread_t parent_thread = pthread_self ();
+  pthread_t sighandler_thread;
+  if (pthread_create (&sighandler_thread, NULL, pull_signals, &parent_thread))
+    {
+      perror ("pthread_create");
+      exit (1);
+    }
+
+  std::cout << pidname.c_str () << std::endl;
+
+  /* Redirect stdin and stdout to /dev/null. */
+  if (! freopen ("/dev/null", "r", stdin))
+    {
+      perror ("freopen");
+      exit (1);
+    }
+  if (! freopen ("/dev/null", "w", stdout))
+    {
+      perror ("freopen");
+      exit (1);
+    }
+
+  std::string errname ("/tmp/octave_error-");
+  errname = errname + hostname.c_str () + ".log";
+  struct stat s_stat;
+  if (stat (errname.c_str (), &s_stat) == 0)
+    {
+      std::string bakname ("/tmp/octave_error-");
+      bakname = bakname + hostname.c_str () + ".bak";
+      if (rename (errname.c_str (), bakname.c_str ()))
+        {
+          perror ("rename");
+          exit (1);
+        }
+    }
+  if (! freopen (errname.c_str (), "w", stderr))
+    {
+      perror ("freopen");
+      exit (1);
+    } 
+
+  struct addrinfo *ai, hints;
+
+  memset ((void *) &hints, 0, sizeof (hints));
+  hints.ai_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_protocol = 0;
+  hints.ai_flags = AI_PASSIVE;
+  if (getaddrinfo (NULL, opts.cmd_port_string ().c_str (), &hints, &ai))
+    {
+      perror ("getaddrinfo");
+      exit (1);
+    }
+
+  // SOCK_CLOEXEC: this file descriptor is only needed here, not in
+  // the Octave server, which will use a file descriptor returned by
+  // accept()
+  int sock = socket (PF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+  if (sock == -1)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  if (bind (sock, ai->ai_addr, ai->ai_addrlen))
+    {
+      perror ("bind");
+      exit (1);
+    }
+
+
+  if (listen (sock, SOMAXCONN))
+    {
+      perror ("listen");
+      exit (1);
+    }
+
+
+  if (getaddrinfo (NULL, opts.data_port_string ().c_str (), &hints, &ai))
+    {
+      perror ("getaddrinfo");
+      exit (1);
+    }
+
+  // _don't_ specify SOCK_CLOEXEC, since the Octave server will call
+  // accept() on this file descriptor
+  int dsock = socket (PF_INET, SOCK_STREAM, 0);
+  if (dsock == -1)
+    {
+      perror ("socket");
+      exit (1);
+    }
+
+  if (bind (dsock, ai->ai_addr, ai->ai_addrlen))
+    {
+      perror ("bind");
+      exit (1);
+    }
+
+  if (listen (dsock, SOMAXCONN))
+    {
+      perror ("listen");
+      exit (1);
+    }
+
+  freeaddrinfo (ai);
+
+  int server_no = -1; // for debugging
+  for(;;)
+    {
+      server_no++;
+      dsprintf ("server_no: %i, trying to accept command stream at port %s\n",
+                server_no, opts.cmd_port_string ().c_str ());
+      int asock = accept (sock, 0, 0);
+      if (asock == -1)
+        {
+          perror ("accept");
+          exit (1);
+        }
+      dsprintf ("%i: accepted command stream\n", server_no);
+      /* Normal production daemon.  Fork, and have the child process
+         the connection.  The parent continues listening. */
+
+      int pid;
+      if ((pid = fork ()) == -1)
+        {
+          perror ("fork");
+          exit (1);
+        }
+      else if (pid == 0) 
+        {
+          // From here on, use only _exit(), not exit(). The signal
+          // handling pthread isn't present in the current process so
+          // it can't cause an exit().
+
+          int tp;
+          if ((tp = fork ()))
+            {
+              if (tp == -1)
+                {
+                  perror ("fork");
+                  _exit (1);
+                }
+              else
+                _exit (0);
+            }
+
+          dsprintf ("%i: child after fork\n", server_no);
+
+          // empty signal mask
+          sigset_t nosigs;
+          if (sigemptyset (&nosigs)
+              || pthread_sigmask (SIG_SETMASK, &nosigs, NULL))
+            {
+              error (0, 0, "could not empty signal mask");
+              _exit (1);
+            }
+
+          // Arguments for exec()ing Octave should include the values
+          // of the current variables asock and dsock, hostname, also
+          // some representation of use_gnutls and cafile. Also
+          // server_no.
+          const int nargs = 2; // made to grow, currently these are
+                               // the '--eval' option and its argument
+          char * args [nargs + 2];
+          args[0] = copy_to_non_const (opts.octave_binary ().c_str ());
+          args[1] = copy_to_non_const ("--eval");
+          std::stringstream eval_arg;
+          eval_arg << "__octave_server__ ("
+                   << asock << ", "
+                   << dsock << ", "
+                   << (opts.use_tls () ? "true" : "false") << ", "
+                   << "'" << opts.auth_file () << "'" << ", "
+                   << "'" << hostname << "'" << ", "
+                   << server_no
+                   << ")";
+          std::string eval_arg_str (eval_arg.str ());
+          args[2] = copy_to_non_const (eval_arg_str.c_str ());
+          args[3] = NULL;
+          
+          // exec() Octave
+          dsprintf ("%i: exec()ing Octave\n", server_no);
+          if (execv (args[0], args))
+            {
+              perror ("execv");
+              _exit (1);
+            }
+
+          // not reached
+        }
+
+      // parent
+
+      waitpid (pid, NULL, 0); // child with pid has forked another child
+
+      close (asock);
+    } // unconditional loop
+
+  // This code is currently not reached since the server parent
+  // process can only be killed by a signal.
+  close (sock);
+  close (dsock);
+  exit (1);
+  // Silence compiler warning.
+  exit (0);
+}
diff -urN parallel-3.1.3/src/octave-pserver.h octave-parallel/src/octave-pserver.h
--- parallel-3.1.3/src/octave-pserver.h	1970-01-01 01:00:00.000000000 +0100
+++ octave-parallel/src/octave-pserver.h	2019-08-02 12:43:39.651207942 +0200
@@ -0,0 +1,76 @@
+/*
+
+Copyright (C) 2019 Olaf Till <i7tiol@t-online.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "config.h"
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <getopt.h>
+
+#include "common.h"
+
+#define N_LONGOPTS 7
+
+class p_cmdline_options
+{
+public:
+
+  p_cmdline_options (int argc, char * const *argv);
+
+  bool use_tls (void) const { return opt_use_tls; }
+
+  bool print_help (void) const { return opt_print_help; }
+
+  const std::string &auth_file (void) const { return opt_auth_file; }
+
+  const std::string &octave_binary (void) const { return opt_octave_binary; }
+
+  int cmd_port (void) const { return opt_cmd_port; }
+
+  int data_port (void) const { return opt_data_port; }
+
+  const std::string &cmd_port_string (void) const
+  { return opt_cmd_port_string; }
+
+  const std::string &data_port_string (void) const
+  { return opt_data_port_string; }
+
+private:
+
+  bool opt_use_tls;
+
+  bool opt_print_help;
+
+  std::string opt_auth_file;
+
+  std::string opt_octave_binary;
+
+  int opt_cmd_port;
+
+  int opt_data_port;
+
+  std::string opt_cmd_port_string;
+
+  std::string opt_data_port_string;
+
+  static
+  struct option known_long_opts[N_LONGOPTS + 1];
+};
diff -urN parallel-3.1.3/src/__octave_server__.cc octave-parallel/src/__octave_server__.cc
--- parallel-3.1.3/src/__octave_server__.cc	1970-01-01 01:00:00.000000000 +0100
+++ octave-parallel/src/__octave_server__.cc	2019-08-02 12:43:39.642208105 +0200
@@ -0,0 +1,790 @@
+/*
+
+Copyright (C) 2002 Hayato Fujiwara <h_fujiwara@users.sourceforge.net>
+Copyright (C) 2010-2019 Olaf Till <i7tiol@t-online.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+// PKG_ADD: autoload ("__octave_server__", "parallel_interface.oct");
+// PKG_DEL: autoload ("__octave_server__", "parallel_interface.oct", "remove");
+
+#include <octave/oct.h>
+
+#include "config.h"
+
+#include <octave/file-io.h>
+#include <octave/sighandlers.h>
+#include <octave/parse.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <iostream>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <netdb.h>
+#include <sys/utsname.h>
+#include <netinet/in.h> // reported necessary for FreeBSD-8
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "parallel-gnutls.h"
+
+static
+int assert_file (std::string &path)
+{
+  OCTAVE__SYS__FILE_STAT stat (path);
+
+  if (! stat.is_reg ())
+    return -1;
+  else
+    return 0;
+}
+
+void
+reval_loop (octave_parallel_stream &cstr)
+{
+  dsprintf ("reval, trying to write and read dummy\n");
+
+  // send and read the final character of the initialization protocol
+  // to and from the client
+  char dummy = '\n';
+  cstr.get_ostream () << dummy;
+  dsprintf ("reval, wrote dummy (%i)\n", dummy);
+  cstr.get_istream () >> std::noskipws >> dummy;
+  dsprintf ("reval, read dummy (%i)\n", dummy);
+
+  if (! cstr.good ())
+    {
+      _p_error ("could not finish initialization");
+      _exit (1);
+    }
+
+  bool firsttime = true;
+
+  dsprintf ("reval, entering loop\n");
+  while (true)
+    {
+      std::string s;
+
+      if (firsttime)
+        {
+          dsprintf ("reval, setting command to 'rehash ()' at first repetition of loop\n");
+          s = "rehash ()\n"; // this avoided some problems
+          firsttime = false;
+        }
+      else
+        {
+          dsprintf ("reval loop, before network_recv_string\n");
+          if (cstr.network_recv_string (s))
+            {
+              _p_error ("error reading command");
+              _exit (1);
+            }
+          dsprintf ("reval loop, after successful network_recv_string\n");
+        }
+
+      bool err;
+      int p_err;
+      SET_ERR (OCTAVE__EVAL_STRING (s, false, p_err, 0), err);
+      dsprintf ("reval loop, after evaluating string\n");
+
+      uint32_t nl = 0;
+      if (err)
+        {
+          dsprintf ("reval loop, evaluation caused error\n");
+          nl = 1;
+        }
+      else if (p_err)
+        {
+          dsprintf ("reval loop, p_err was set\n");
+          nl = 1;
+        }
+      if (nl)
+        {
+          dsprintf ("reval loop, before sending error indication\n");
+          if (cstr.network_send_4byteint (nl, true))
+            {
+              _p_error ("error sending error code");
+              _exit (1);
+            }
+          dsprintf ("reval loop, after successful sending error indication\n");
+        }
+      else
+        {
+          dsprintf ("reval loop, no error, caring for Octave command number\n");
+          if (octave_completion_matches_called)
+            octave_completion_matches_called = false;
+          else
+            OCTAVE__COMMAND_EDITOR::increment_current_command_number ();
+          dsprintf ("reval loop, no error, after caring for Octave command number\n");
+        }
+    }
+}
+
+DEFUN_DLD (__octave_server__, args, ,
+           "-*- texinfo -*-\n\
+@deftypefn {Loadable Function} {} __octave_server__ ()\n\
+Undocumented internal function.\n\
+@end deftypefn")
+{
+  // Contrary to what is done in the client side function connect.cc,
+  // it is not necessarily always explicitely cared here for closing
+  // of sockets and freeing of allocated memory in cases of
+  // error. Since this function exits or returns in case of an
+  // internal error, there is sometimes no need to do this. Returning
+  // (due to exceptions) should be as good as exiting, since the
+  // server is started in a way that leads to exiting Octave as soon
+  // as the server returns.
+  //
+  // Originally, it was thought that deallocation of anything which
+  // uses credentials has to be carefully provided here also, since
+  // the destructor of the ref-counted credentials must be called in
+  // the end to zero sensitive data before deallocation. This may not
+  // be true, since the OS should zero any memory page given to a new
+  // process.
+
+  octave_value_list retval;
+
+  std::string fname ("__octave_server__");
+
+  dsprintf ("%s: just started\n", fname.c_str ());
+
+  // arguments: asock, dsock, use_gnutls, cafile, hostname, server_no
+  if (args.length () != 6)
+    {
+      _p_error ("%s: six arguments required", fname.c_str ());
+      _exit (1);
+    }
+  // file descriptor for command connection (accepted socket)
+  int asock;
+  CHECK_ERROR_EXIT1 (asock = args(0).int_value (),
+                     "%s: could not convert argument 1 to int",
+                     fname.c_str ());
+  // file descriptor for data connection (socket in listening state)
+  int dsock;
+  CHECK_ERROR_EXIT1 (dsock = args(1).int_value (),
+                     "%s: could not convert argument 2 to int",
+                     fname.c_str ());
+  // use TLS
+  bool use_gnutls;
+  CHECK_ERROR_EXIT1 (use_gnutls = args(2).bool_value (),
+                     "%s: could not convert argument 3 to bool",
+                     fname.c_str ());
+  // custom authentication file
+  std::string cafile;
+  CHECK_ERROR_EXIT1 (cafile = args(3).string_value (),
+                     "%s: could not convert argument 4 to string",
+                     fname.c_str ());
+  // hostname
+  std::string hostname;
+  CHECK_ERROR_EXIT1 (hostname = args(4).string_value (),
+                     "%s: could not convert argument 5 to string",
+                     fname.c_str ());
+  // server number for debugging
+  int server_no;
+  CHECK_ERROR_EXIT1 (server_no = args(5).int_value (),
+                     "%s: could not convert argument 6 to int",
+                     fname.c_str ());
+
+  // A negative integer might be sent as Octave data, and Octave
+  // doesn't care about coding of negative integers. (I know, there
+  // probably will never be a current C-compiler with something
+  // different than twos complement. But the C-standard allows for
+  // it.)
+  if (octave_parallel_stream::signed_int_rep ())
+    {
+      _p_error ("This machine doesn't seem to use twos complement as negative integer representation. If you want this to be supported, please file a bug report.");
+
+      _exit (1);
+    }
+
+  // avoid dumping octave_core if killed by a signal
+  OCTAVE__FEVAL ("sigterm_dumps_octave_core", octave_value (0), 0);
+  OCTAVE__FEVAL ("sighup_dumps_octave_core", octave_value (0), 0);
+
+  dsprintf ("%i: Octave server before start of communication\n", server_no);
+
+#ifdef HAVE_LIBGNUTLS
+  struct __ccredguard
+  {
+    octave_parallel_gnutls_srp_client_credentials *__c;
+    __ccredguard (void) : __c (NULL) { }
+    ~__ccredguard (void) { if (__c && ! __c->check_ref ()) delete __c; }
+    octave_parallel_gnutls_srp_client_credentials *__get (void)
+    { return __c; }
+    void __set (octave_parallel_gnutls_srp_client_credentials *__ic)
+    { __c = __ic; }
+    void __release (void) { __c = NULL; }
+  }  __ccg;
+  octave_parallel_gnutls_srp_client_credentials *ccred;
+
+  struct __scredguard
+  {
+    octave_parallel_gnutls_srp_server_credentials *__c;
+    __scredguard (void) : __c (NULL) { }
+    ~__scredguard (void) { if (__c && ! __c->check_ref ()) delete __c; }
+    octave_parallel_gnutls_srp_server_credentials *__get (void)
+    { return __c; }
+    void __set (octave_parallel_gnutls_srp_server_credentials *__ic)
+    { __c = __ic; }
+    void __release (void) { __c = NULL; }
+  }  __scg;
+  octave_parallel_gnutls_srp_server_credentials *scred;
+
+  if (use_gnutls)
+    {
+      gnutls_global_init (); 
+#ifdef HAVE_LIBGNUTLS_EXTRA
+      gnutls_global_init_extra ();  // for SRP
+      parallel_gnutls_set_mem_functions ();
+#endif
+
+      dsprintf ("%i: after initializing gnutls\n", server_no);
+
+      // generate credentials
+      if (! cafile.length ())
+        {
+#ifdef HAVE_OCTAVE_CONFIG_FCNS
+          std::string octave_home = octave::config::octave_home ();
+#else
+          extern std::string Voctave_home;
+          std::string octave_home = Voctave_home;
+#endif
+          cafile = octave_home +
+            OCTAVE__SYS__FILE_OPS::dir_sep_str () + "share" +
+            OCTAVE__SYS__FILE_OPS::dir_sep_str () + "octave" +
+            OCTAVE__SYS__FILE_OPS::dir_sep_str () +
+            "parallel-srp-data" +
+            OCTAVE__SYS__FILE_OPS::dir_sep_str () + "server" +
+            OCTAVE__SYS__FILE_OPS::dir_sep_str () + "passwd";
+          if (assert_file (cafile))
+            {
+              octave_value_list f_args (1);
+              f_args(0) = octave_value ("prefix");
+              octave_value_list f_ret;
+              CHECK_ERROR_EXIT1 (f_ret = OCTAVE__FEVAL ("pkg", f_args, 1),
+                                 "%s: could not get prefix from pkg",
+                                 fname.c_str ());
+              CHECK_ERROR_EXIT1 (cafile = f_ret(0).string_value (),
+                                 "%s: could not convert output of pkg ('prefix') to string)",
+                                 fname.c_str ());
+              cafile = cafile + OCTAVE__SYS__FILE_OPS::dir_sep_str () +
+                "parallel-srp-data" +
+                OCTAVE__SYS__FILE_OPS::dir_sep_str () + "server" +
+                OCTAVE__SYS__FILE_OPS::dir_sep_str () + "passwd";
+              if (assert_file (cafile))
+                {
+                  _p_error ("%s: no regular file found at default password file paths",
+                            fname.c_str ());
+                  _exit (1);
+                }
+            }
+        }
+      else if (assert_file (cafile))
+        {
+          _p_error ("%s: no regular file found at password file path given by user",
+                    fname.c_str ());
+          _exit (1);
+        }
+      __scg.__set (scred =
+                   new octave_parallel_gnutls_srp_server_credentials
+                   (cafile));
+      dsprintf ("%i: after generating credentials\n", server_no);
+      if (! __scg.__get ()->check_cred ())
+        {
+          _p_error ("%s: could not create credentials",
+                    fname.c_str ());
+          _exit (1);
+        }
+    }
+#endif // HAVE_LIBGNUTLS
+
+  // determine own number of usable processor cores
+  uint32_t nproc = num_processors (NPROC_CURRENT);
+
+  // The servers command stream will not be inserted into a
+  // connection object.
+  octave_parallel_streambuf *cmd_strb;
+#ifdef HAVE_LIBGNUTLS
+  if (use_gnutls)
+    {
+      dsprintf ("%i: will generate gnutls streambuf\n", server_no);
+      cmd_strb = new octave_parallel_gnutls_streambuf
+        (asock, scred, true);
+      __scg.__release ();
+      dsprintf ("%i: generated gnutls streambuf\n", server_no);
+    }
+  else
+#endif
+    cmd_strb = new octave_parallel_socket_streambuf (asock, true);
+  octave_parallel_stream cmd_str (cmd_strb);
+  if (! cmd_str.good ())
+    {
+      _p_error ("could not create command stream");
+      _exit (1);
+    }
+
+  uint32_t nhosts;
+  cmd_str.network_recv_4byteint (nhosts);
+  dsprintf ("%i: received nhosts (%i), good: %i\n", server_no, nhosts, cmd_str.good ());
+
+  cmd_str.network_send_4byteint (nproc, true);
+  dsprintf ("%i: sent nproc (%u), good: %i\n", server_no, nproc, cmd_str.good ());
+
+  uint32_t me;
+  cmd_str.network_recv_4byteint (me);
+  dsprintf ("%i: received me (%i), good: %i\n", server_no, me, cmd_str.good ());
+
+  std::string uuid;
+  cmd_str.network_recv_string (uuid);
+  dsprintf ("%i: received uuid (%s), good: %i\n", server_no, uuid.c_str (), cmd_str.good ());
+
+  if (! cmd_str.good ()) // check before using the received 'nhosts'
+    {
+      _p_error ("communication error in initialization");
+      _exit (1);
+    }
+  Array<std::string> hosts (dim_vector (nhosts, 1));
+  for (uint32_t i = 0; i < nhosts; i++)
+    {
+      cmd_str.network_recv_string (hosts(i));
+      dsprintf ("%i: received hostname no %i (%s)\n", server_no, i, hosts(i).c_str ());
+    }
+
+  dsprintf ("will now change name of error file\n");
+  std::string errname = std::string ("/tmp/octave_error-") + hostname.c_str ()
+    + "_" + uuid.c_str () + ".log";
+  struct stat s_stat;
+  if (stat (errname.c_str (), &s_stat) == 0)
+    {
+      std::string bakname ("/tmp/octave_error-");
+      bakname = bakname + hostname.c_str () +
+        "_" + uuid.c_str () + ".bak";
+      if (rename (errname.c_str (), bakname.c_str ()))
+        {
+          perror ("rename");
+          _exit (1);
+        }
+    }
+  if (! freopen (errname.c_str (), "w", stderr))
+    {
+      perror ("freopen");
+      _exit (1);
+    }
+
+  std::string directory;
+  cmd_str.network_recv_string (directory);
+  dsprintf ("%i: received directory (%s)\n", server_no, directory.c_str ());
+
+#define BUFLEN 1024
+  struct __pwguard
+  {
+    char *__pw;
+    int __len;
+    __pwguard (int __alen) : __pw (new char[__alen]), __len (__alen) { }
+    void __free (void)
+    {
+      if (__pw)
+        {
+          memset ((void *) __pw, 0, __len);
+          delete [] __pw;
+          __pw = NULL;
+        }
+    }
+    ~__pwguard (void) { __free (); }
+    char *__get (void) { return __pw; }
+  } __pwg (BUFLEN);
+  if (use_gnutls)
+    {
+      cmd_str.network_recv_string (__pwg.__get (), BUFLEN);
+      if (me == nhosts) // we won't need it 
+        __pwg.__free ();
+      dsprintf ("%i: received password (%s)\n", server_no, __pwg.__get ());
+    }
+
+  if (! cmd_str.good ())
+    {
+      _p_error ("communication error in initialization");
+      _exit (1);
+    }
+
+  // client may shut down before starting data connections (if it was
+  // unable to establish all command connections)
+  struct pollfd pfd[2];
+  pfd[0].fd = asock;
+  pfd[0].events = POLLIN | POLLHUP; // POLLHUP meaningless here?
+  pfd[0].revents = 0;
+  pfd[1].fd = dsock;
+  pfd[1].events = POLLIN; // will be set if accept is possible
+  pfd[1].revents = 0;
+  if (poll (pfd, 2, -1) == -1)
+    {
+      _p_error ("error in poll()");
+      _exit (1);
+    }
+  if (pfd[0].revents)
+    {
+      _p_error ("unexpected event at command socket");
+      _exit (1);
+    }
+
+  octave_parallel_network *network;
+  struct __netwguard
+  {
+    octave_parallel_network *__n;
+    __netwguard (octave_parallel_network *__an) : __n (__an)
+    { __n->get_ref (); }
+    ~__netwguard (void) { if (__n->release_ref () <= 0) delete __n; }
+  } __ng (network = new octave_parallel_network (nhosts + 1));
+
+  for (uint32_t i = 0; i < me; i++)
+    {
+      //      recv;
+
+      dsprintf ("%i: trying to accept data connection, %i\n", server_no, i);
+      int not_connected = 1;
+      for (int j = 0; j < N_CONNECT_RETRIES; j++)
+        {
+          struct sockaddr_in rem_addr;
+          socklen_t addrlen = sizeof (rem_addr);
+          int adsock = accept (dsock, (sockaddr *) &rem_addr, &addrlen);
+          if (adsock == -1)
+            {
+              perror ("accept, data stream");
+              _exit (1);
+            }
+          dsprintf ("server %i, host %i, retry %i, accept successful\n", server_no, i, j);
+          if (addrlen > sizeof (rem_addr))
+            {
+              perror ("accept, data stream, address buffer to short");
+              _exit (1);
+            }
+          struct __sockguard
+          {
+            __sockguard (int __isock) { __sock = __isock; }
+            ~__sockguard (void) { if (__sock > -1) close (__sock); }
+            void __release (void) { __sock = -1; }
+            int __sock;
+          } __sockg (adsock);
+#define HOSTNAMEBUFLEN 257
+          char peername[HOSTNAMEBUFLEN];
+          if (getnameinfo ((sockaddr *) &rem_addr, addrlen,
+                           (char *) peername, HOSTNAMEBUFLEN,
+                           NULL, 0, 0))
+            {
+              _p_error ("getnameinfo returned an error");
+              _exit (1);
+            }
+
+          octave_parallel_connection *conn =
+            new octave_parallel_connection
+            (peername, true, uuid.c_str ());
+
+          // you don't know the position to insert the connection
+          // (protecting it) yet, an exception may be thrown before
+          // you know it
+          struct __connguard
+          {
+            __connguard (octave_parallel_connection *__ipt)
+            { __pt = __ipt; }
+            ~__connguard (void) { if (__pt) delete __pt; }
+            void __set (octave_parallel_connection *__ipt)
+            { __pt = __ipt; }
+            octave_parallel_connection *__pt;
+            void __release (void) { __pt = NULL; }
+          } __conng (conn);
+
+#ifdef HAVE_LIBGNUTLS
+          if (use_gnutls)
+            {
+              conn->insert_data_stream
+                (new octave_parallel_stream
+                 (new octave_parallel_gnutls_streambuf
+                  (adsock, scred, true)));
+              dsprintf ("server %i, host %i, retry %i, generated gnutls streambuf\n", server_no, i, j);
+            }
+          else
+#endif
+            conn->insert_data_stream
+              (new octave_parallel_stream
+               (new octave_parallel_socket_streambuf (adsock, true)));
+
+          __sockg.__release ();
+
+          if (! conn->get_data_stream ()->good ())
+            {
+              _p_error ("could not create data stream to %s", peername);
+              _exit (1);
+            }
+
+          std::string duuid;
+          conn->get_data_stream ()->network_recv_string (duuid);
+          dsprintf ("server %i, host %i, retry %i, received uuid (%s)\n", server_no, i, j, duuid.c_str ());
+                 
+          uint32_t host_n;
+          conn->get_data_stream ()->network_recv_4byteint (host_n);
+          dsprintf ("server %i, host %i, retry %i, received host_n (%i)\n", server_no, i, j, host_n);
+
+          if (! conn->get_data_stream ()->good ())
+            {
+              _p_error ("communication error in initialization");
+              _exit (1);
+            }
+
+          if (uuid.compare (duuid))
+            {
+              // a different call to 'connect', i.e. a different network
+              conn->get_data_stream ()->network_send_4byteint (-1);
+              if (conn->delete_data_stream ())
+                {
+                  _p_error ("could not delete data stream");
+                  _exit (1);
+                }
+              dsprintf ("server %i, host %i, retry %i, sent result -1\n", server_no, i, j);
+              sleep (1);
+            }
+          else if (me <= host_n || network->is_connection (host_n))
+            {
+              // we should never get here (since duuid == uuid)
+              conn->get_data_stream ()->network_send_4byteint (-2);
+              _p_error ("server %i, host %i, retry %i, internal error, unexpected host id %i, is_connection(host id): %i", server_no, i, j, host_n,
+                        network->is_connection (host_n));
+              _exit (1);
+            }
+          else
+            {
+              conn->get_data_stream ()->network_send_4byteint (0);
+              int err = conn->connection_read_header ();
+              minimal_write_header
+                (conn->get_data_stream ()->get_ostream ());
+              if (err || ! conn->get_data_stream ()->good ())
+                {
+                  _p_error ("communication error in initialization");
+                  _exit (1);
+                }
+              network->insert_connection (conn, host_n);
+              __conng.__release ();
+              not_connected = 0;
+              dsprintf ("server %i, host %i, retry %i, good result sent, header read, header written and data stream good, breaking\n", server_no, i, j);
+              break;
+            }
+        }
+      if (not_connected)
+        {
+          _p_error ("maximum number of connect retries exceeded");
+          _exit (-1);
+        }
+    }
+
+  close (dsock);
+
+
+  // a pseudo-connection, representing the own node in the network
+  octave_parallel_connection *conn =
+    new octave_parallel_connection (true, uuid.c_str ());
+
+  network->insert_connection (conn, me);
+  dsprintf ("server %i inserted pseudoconnection at %i\n", server_no, me);
+
+  // store number of available processor cores at the own machine,
+  // although this is not necessary (but we have this information
+  // here...)
+  conn->set_nproc (nproc);
+
+#ifdef HAVE_LIBGNUTLS
+  if (use_gnutls && me < nhosts)
+    {
+      const char *username =
+        static_cast<octave_parallel_gnutls_streambuf*>(cmd_strb)->
+        server_get_username ();
+      dsprintf ("server %i determined username %s from command stream, will now allocate client credentials (for data connections) with this username and password %s\n", server_no, username, __pwg.__get ());
+
+      __ccg.__set (ccred =
+                   new octave_parallel_gnutls_srp_client_credentials
+                   (username, __pwg.__get ()));
+    }
+#endif
+
+
+  for (uint32_t i = me + 1; i <= nhosts; i++)
+    {
+      // connect;
+      dsprintf ("connect, server %i, host %i\n", server_no, i);
+
+      struct addrinfo *ai = NULL, hints;
+      memset ((void *) &hints, 0, sizeof (hints));
+      hints.ai_family = AF_INET;
+      hints.ai_socktype = SOCK_STREAM;
+      hints.ai_protocol = 0;
+      hints.ai_flags = 0;
+      if (getaddrinfo (hosts(i - 1).c_str (), "12501", &hints, &ai))
+        {
+          _p_error ("getaddrinfo returned an error");
+          _exit (1);
+        }
+      struct __aiguard
+      {
+        __aiguard (struct addrinfo *__iai) { __ai = __iai; }
+        ~__aiguard (void) { if (__ai) freeaddrinfo (__ai); }
+        struct addrinfo *__ai;
+      } __aig (ai);
+
+      int not_connected = 1;
+      for (int j = 0; j < N_CONNECT_RETRIES; j++)
+        {
+          int dsock = socket (PF_INET, SOCK_STREAM, 0);
+          if (dsock == -1)
+            {
+              perror ("socket");
+              _exit (1);
+            }
+          struct __sockguard
+          {
+            __sockguard (int __isock) { __sock = __isock; }
+            ~__sockguard (void) { if (__sock > -1) close (__sock); }
+            void __release (void) { __sock = -1; }
+            int __sock;
+          } __sockg (dsock);
+
+          if (connect (dsock, ai->ai_addr, ai->ai_addrlen) == 0)
+            {
+              dsprintf ("connect, server %i, host %i, retry %i, connect succesful\n", server_no, i, j);
+              octave_parallel_connection *conn =
+                new octave_parallel_connection
+                (hosts(i - 1).c_str (), true, uuid.c_str ());
+              network->insert_connection (conn, i);
+
+#ifdef HAVE_LIBGNUTLS
+              if (use_gnutls)
+                {
+                  conn->insert_data_stream
+                    (new octave_parallel_stream
+                     (new octave_parallel_gnutls_streambuf
+                      (dsock, ccred, false)));
+                  __ccg.__release ();
+                  dsprintf ("connect, server %i, host %i, retry %i, generated gnutls streambuf\n", server_no, i, j);
+                }
+              else
+#endif
+                conn->insert_data_stream
+                  (new octave_parallel_stream
+                   (new octave_parallel_socket_streambuf (dsock, false)));
+              __sockg.__release ();
+              if (! conn->get_data_stream ()->good ())
+                {
+                  _p_error ("could not create data stream to %s",
+                            hosts(i - 1).c_str ());
+                  _exit (1);
+                }
+
+              conn->get_data_stream ()->
+                network_send_string (uuid.c_str ());
+              dsprintf ("connect, server %i, host %i, retry %i, uuid written (%s)\n", server_no, i, j, uuid.c_str ());
+
+              conn->get_data_stream ()->network_send_4byteint (me,
+                                                                       true);
+              dsprintf ("connect, server %i, host %i, retry %i, 'me' written (%i)\n", server_no, i, j, me);
+
+              int32_t res;
+              conn->get_data_stream ()->network_recv_4byteint (res);
+
+              if (! conn->get_data_stream ()->good ())
+                {
+                  _p_error ("communication error in initialization");
+                  _exit (1);
+                }
+
+              if (res == -1)
+                {
+                  if (conn->delete_data_stream ())
+                    {
+                      _p_error ("could not delete data stream");
+                      _exit (1);
+                    }
+
+                  dsprintf ("connect, server %i, host %i, retry %i, sleeping after bad result\n", server_no, i, j);
+                  usleep (5000);
+                }
+              else if (res)
+                {
+                  _p_error ("unexpected error in remote server");
+                  _exit (1);
+                }
+              else
+                {
+                  minimal_write_header
+                    (conn->get_data_stream ()->get_ostream ());
+                  if (conn->connection_read_header () ||
+                      ! conn->get_data_stream ()->good ())
+                    {
+                      _p_error ("communication error in initialization");
+                      _exit (1);
+                    }
+                  not_connected = 0;
+                  dsprintf ("connect, server %i, host %i, retry %i, good result read, header written and read and datastream good, breaking\n", server_no, i, j);
+                  break; 
+                }
+            }
+          else if (errno != ECONNREFUSED && errno != EINTR)
+            {
+              perror ("connect");
+              break;
+            }
+          else
+            usleep (5000);
+        }
+
+      if (not_connected)
+        {
+          _p_error ("unable to connect to %s", hosts(i - 1).c_str ());
+          _exit (1);
+        }
+    }
+
+  octave_parallel_connections *conns = new octave_parallel_connections
+    (network, uuid.c_str (), true);
+  octave_value sockets (conns);
+
+  __pwg.__free ();
+
+#ifdef HAVE_OCTAVE_INTERPRETER_H
+  OCTAVE__INTERPRETER::the_interpreter () -> interactive (false);
+#else
+  interactive = false;
+#endif
+
+  // install 'sockets' as Octave variable
+  OCTAVE__INTERPRETER__SYMBOL_TABLE__ASSIGN ("sockets", sockets);
+  dsprintf ("'sockets' installed\n");
+
+  int cd_ok = OCTAVE__SYS__ENV::chdir (directory.c_str ());
+  if (! cd_ok)
+    {
+      OCTAVE__SYS__ENV::chdir ("/tmp");
+      dsprintf ("performed chdir to /tmp\n");
+    }
+  else
+    dsprintf ("performed chdir to %s\n", directory.c_str ());
+
+  dsprintf ("calling function reval_loop\n");
+  reval_loop (cmd_str); // does not return
+
+  return retval;
+}
diff -urN parallel-3.1.3/src/parallel-gnutls.h octave-parallel/src/parallel-gnutls.h
--- parallel-3.1.3/src/parallel-gnutls.h	2018-08-03 09:41:42.566478128 +0200
+++ octave-parallel/src/parallel-gnutls.h	2019-08-02 12:43:39.654207887 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
@@ -102,36 +102,10 @@
 
 #define N_CONNECT_RETRIES 10
 
-/* define some of the following for debugging, but take care:
-   sensitive data (e.g. the password) will be written to standard
-   error and to logfiles */
-#undef octave_parallel_debug_server
-// #define octave_parallel_debug_server 1
-#undef octave_parallel_debug_client
-// #define octave_parallel_debug_client 1
-#undef octave_parallel_debug_lib
-// #define octave_parallel_debug_lib 1
-
-#ifdef octave_parallel_debug_server
-  #define dsprintf(...) fprintf (stderr, __VA_ARGS__); fflush (stderr);
-#else
-  #define dsprintf(...)
-#endif
-
-#ifdef octave_parallel_debug_client
-  #define dcprintf(...) fprintf (stderr, __VA_ARGS__);
-#else
-  #define dcprintf(...)
-#endif
-
-#ifdef octave_parallel_debug_lib
-  #define dlprintf(...) fprintf (stderr, __VA_ARGS__); fflush (stderr);
-#else
-  #define dlprintf(...)
-#endif
-
 // parallel package includes
 
+#include "parallel-gnutls-nonoctave.h"
+
 #include "error-helpers.h"
 
 #ifdef HAVE_LIBGNUTLS
diff -urN parallel-3.1.3/src/parallel-gnutls-nonoctave.h octave-parallel/src/parallel-gnutls-nonoctave.h
--- parallel-3.1.3/src/parallel-gnutls-nonoctave.h	1970-01-01 01:00:00.000000000 +0100
+++ octave-parallel/src/parallel-gnutls-nonoctave.h	2019-08-02 12:43:39.653207906 +0200
@@ -0,0 +1,52 @@
+/*
+
+Copyright (C) 2019 Olaf Till <i7tiol@t-online.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef __OCT_PARALLEL_GNUTLS_NONOCTAVE__
+
+#define __OCT_PARALLEL_GNUTLS__
+
+/* define some of the following for debugging, but take care:
+   sensitive data (e.g. the password) will be written to standard
+   error and to logfiles */
+#undef octave_parallel_debug_server
+// #define octave_parallel_debug_server 1
+#undef octave_parallel_debug_client
+// #define octave_parallel_debug_client 1
+#undef octave_parallel_debug_lib
+// #define octave_parallel_debug_lib 1
+
+#ifdef octave_parallel_debug_server
+  #define dsprintf(...) fprintf (stderr, __VA_ARGS__); fflush (stderr);
+#else
+  #define dsprintf(...)
+#endif
+
+#ifdef octave_parallel_debug_client
+  #define dcprintf(...) fprintf (stderr, __VA_ARGS__);
+#else
+  #define dcprintf(...)
+#endif
+
+#ifdef octave_parallel_debug_lib
+  #define dlprintf(...) fprintf (stderr, __VA_ARGS__); fflush (stderr);
+#else
+  #define dlprintf(...)
+#endif
+
+#endif // __OCT_PARALLEL_GNUTLS_NONOCTAVE__
diff -urN parallel-3.1.3/src/pconnect.cc octave-parallel/src/pconnect.cc
--- parallel-3.1.3/src/pconnect.cc	2018-08-03 09:41:42.570478207 +0200
+++ octave-parallel/src/pconnect.cc	2019-08-02 12:43:39.654207887 +0200
@@ -5,7 +5,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
@@ -25,8 +25,6 @@
 
 #include "config.h"
 
-#include <octave/oct-env.h>
-
 #include <sys/socket.h>
 #include <errno.h>
 #include <netdb.h>
@@ -533,7 +531,7 @@
               dcprintf ("hostname %i written (%s)\n", j, hosts(j).c_str ());
             }
 
-          std::string directory = octave_env::get_current_directory ();
+          std::string directory = OCTAVE__SYS__ENV::get_current_directory ();
 
           conn->get_cmd_stream ()->network_send_string (directory.c_str ());
           dcprintf ("directory written (%s)\n", directory.c_str ());
diff -urN parallel-3.1.3/src/pserver.cc octave-parallel/src/pserver.cc
--- parallel-3.1.3/src/pserver.cc	2018-08-03 09:41:42.570478207 +0200
+++ octave-parallel/src/pserver.cc	1970-01-01 01:00:00.000000000 +0100
@@ -1,1151 +0,0 @@
-/*
-
-Copyright (C) 2002 Hayato Fujiwara <h_fujiwara@users.sourceforge.net>
-Copyright (C) 2010-2018 Olaf Till <i7tiol@t-online.de>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; If not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-// PKG_ADD: autoload ("pserver", "parallel_interface.oct");
-// PKG_DEL: autoload ("pserver", "parallel_interface.oct", "remove");
-
-#include <octave/oct.h>
-
-#include "config.h"
-
-#include <octave/oct-env.h>
-#include <octave/file-io.h>
-#include <octave/sighandlers.h>
-#include <octave/parse.h>
-#include <octave/cmd-edit.h>
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <iostream>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <netdb.h>
-#include <sys/utsname.h>
-#include <netinet/in.h> // reported necessary for FreeBSD-8
-
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "parallel-gnutls.h"
-
-// Octave > 3.2.4 does not have these in a header file, but in
-// sighandlers.cc, and uses gnulib:: for these. So this is copied from
-// Octave-3.2.4.
-#define BLOCK_SIGNAL(sig, nvar, ovar) \
-  do \
-    { \
-      sigemptyset (&nvar); \
-      sigaddset (&nvar, sig); \
-      sigemptyset (&ovar); \
-      sigprocmask (SIG_BLOCK, &nvar, &ovar); \
-    } \
-  while (0)
-
-#if !defined (SIGCHLD) && defined (SIGCLD)
-#define SIGCHLD SIGCLD
-#endif
-
-// FIXME: Octave-3.2.4 had HAVE_POSIX_SIGNALS in config.h, newer
-// Octave has not (probably due to using gnulib?). We have not this
-// test in configure now, but assume HAVE_POSIX_SIGNALS defined.
-#define BLOCK_CHILD(nvar, ovar) BLOCK_SIGNAL (SIGCHLD, nvar, ovar)
-#define UNBLOCK_CHILD(ovar) sigprocmask (SIG_SETMASK, &ovar, 0)
-// #else
-// #define BLOCK_CHILD(nvar, ovar) ovar = sigblock (sigmask (SIGCHLD))
-// #define UNBLOCK_CHILD(ovar) sigsetmask (ovar)
-
-static
-int assert_file (std::string &path)
-{
-  OCTAVE__SYS__FILE_STAT stat (path);
-
-  if (! stat.is_reg ())
-    return -1;
-  else
-    return 0;
-}
-
-/* children are not killed on parent exit; for that octave_child_list
-   can not be used and an own SIGCHLD handler is needed */
-
-static
-bool pserver_child_event_handler (pid_t pid, int ev)
-{
-  return 1; // remove child from octave_child_list
-}
-
-void
-reval_loop (octave_parallel_stream &cstr)
-{
-  dsprintf ("reval, trying to write and read dummy\n");
-
-  // send and read the final character of the initialization protocol
-  // to and from the client
-  char dummy = '\n';
-  cstr.get_ostream () << dummy;
-  dsprintf ("reval, wrote dummy (%i)\n", dummy);
-  cstr.get_istream () >> std::noskipws >> dummy;
-  dsprintf ("reval, read dummy (%i)\n", dummy);
-
-  if (! cstr.good ())
-    {
-      error ("could not finish initialization");
-      _exit (1);
-    }
-
-  bool firsttime = true;
-
-  dsprintf ("reval, entering loop\n");
-  while (true) // function does not return
-    {
-      std::string s;
-
-      if (firsttime)
-        {
-          dsprintf ("reval, setting command to 'rehash ()' at first repetition of loop\n");
-          s = "rehash ()\n"; // this avoided some problems
-          firsttime = false;
-        }
-      else
-        {
-          dsprintf ("reval loop, before network_recv_string\n");
-          if (cstr.network_recv_string (s))
-            {
-              error ("error reading command");
-              _exit (1);
-            }
-          dsprintf ("reval loop, after successful network_recv_string\n");
-        }
-
-      bool err;
-      int p_err;
-      SET_ERR (OCTAVE__EVAL_STRING (s, false, p_err, 0), err);
-      dsprintf ("reval loop, after evaluating string\n");
-
-      uint32_t nl = 0;
-      if (err)
-        {
-          dsprintf ("reval loop, evaluation caused error\n");
-          nl = 1;
-        }
-      else if (p_err)
-        {
-          dsprintf ("reval loop, p_err was set\n");
-          nl = 1;
-        }
-      if (nl)
-        {
-          dsprintf ("reval loop, before sending error indication\n");
-          if (cstr.network_send_4byteint (nl, true))
-            {
-              error ("error sending error code");
-              _exit (1);
-            }
-          dsprintf ("reval loop, after successful sending error indication\n");
-        }
-      else
-        {
-          dsprintf ("reval loop, no error, caring for Octave command number\n");
-          if (octave_completion_matches_called)
-            octave_completion_matches_called = false;
-          else
-            command_editor::increment_current_command_number ();
-          dsprintf ("reval loop, no error, after caring for Octave command number\n");
-        }
-    }
-}
-
-static int check_and_write_pidfile (const char *fname, int pid)
-{
-  int fd, ret, nread;
-
-  while ((fd = open (fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0 &&
-         errno == EINTR);
-  if (fd < 0)
-    return -1;
-
-  struct flock fl;
-  fl.l_type = F_WRLCK;
-  fl.l_whence = SEEK_SET;
-  fl.l_start = 0;
-  fl.l_len = 0;
-  while ((ret = fcntl (fd, F_SETLKW, &fl)) < 0 && errno == EINTR);
-  if (ret < 0)
-    {
-      close (fd);
-      return -1;
-    }
-
-  char b;
-  while ((nread = read (fd, &b, 1)) < 0 && errno == EINTR);
-  if (nread < 0 || nread == 1)
-    {
-      close (fd);
-      return -1;
-    }
-
-  if (lseek (fd, 0, SEEK_SET))
-    {
-      close (fd);
-      return -1;
-    }
-
-  FILE *fstr;
-  if (! (fstr = fdopen (fd, "w+")))
-    {
-      close (fd);
-      return -1;
-    }
-
-  if (fprintf (fstr, "%i", pid) < 0)
-    {
-      fclose (fstr);
-      return -1;
-    }
-
-  if (fclose (fstr) == EOF)
-    return -1;
-  else
-    return 0;
-}
-
-DEFUN_DLD (pserver, args, ,
-           "-*- texinfo -*-\n\
-@deftypefn {Loadable Function} {} pserver ()\n\
-@deftypefnx {Loadable Function} {} pserver (@var{options})\n\
-This function starts a server of the parallel cluster and should be called once at any server machine.\n\
-\n\
-It is important to call this function in a way assuring that Octave is\n\
-quit as soon as the function returns, i.e. call it e.g. like\n\
-@code{octave --eval \"pserver\"} or @code{octave --eval \"pserver\n\
-(struct ('fieldname', value))\"}.\n\
-\n\
-If a directory path corresponding to the current directory of the\n\
-client exists on the server machine, it will be used as the servers\n\
-current directory for the respective client (multiple clients are\n\
-possible). Otherwise, @code{/tmp} will be used. The Octave functions\n\
-the server is supposed to call and the files it possibly has to access\n\
-must be available at the server machine. This can e.g. be achieved by\n\
-having the server machine mount a network file system (which is\n\
-outside the scope of this package documentation).\n\
-\n\
-The parent server process can only be terminated by sending it a\n\
-signal. The pid of this process, as long as it is running, will be\n\
-stored in the file @code{/tmp/.octave-<hostname>.pid}.\n\
-\n\
-If a connection is accepted from a client, the server collects a\n\
-network identifier and the names of all server machines of the network\n\
-from the client. Then, connections are automatically established\n\
-between all machines of the network. Data exchange will be possible\n\
-between all machines (client or server) in both directions. Commands\n\
-can only be sent from the client to any server.\n\
-\n\
-The opaque variable holding the network connections, in the same order\n\
-as in the corresponding variable returned by @code{pconnect}, is\n\
-accessible under the variable name @code{sockets} at the server\n\
-side. Do not overwrite or clear this variable. The own server machine\n\
-will also be contained at some index position of this variable, but\n\
-will not correspond to a real connection. See @code{pconnect} for\n\
-further information.\n\
-\n\
-@var{options}: structure of options; field @code{use_tls} is\n\
-@code{true} by default (TLS with SRP authentication); if set to\n\
-@code{false}, there will be no encryption or authentication. Field\n\
-@code{auth_file} can be set to an alternative path to the file with\n\
-authentication information (see below).\n\
-\n\
-The client and the server must both use or both not use TLS. If TLS is\n\
-switched off, different measures must be taken to protect ports 12501\n\
-and 12502 at the servers and the client against unauthorized access;\n\
-e.g. by a firewall or by physical isolation of the network.\n\
-\n\
-For using TLS, authorization data must be present at the server\n\
-machine. These data can conveniently be generated by\n\
-@code{parallel_generate_srp_data}; the helptext of the latter function\n\
-documents the expected location of these data.\n\
-\n\
-The SRP password will be sent over the encrypted TLS channel from the\n\
-client to each server, to avoid permanently storing passwords at the\n\
-server for server-to-server data connections. Due to inevitable usage\n\
-of external libraries, memory with sensitive data can, however, be on\n\
-the swap device even after shutdown of the application.\n\
-\n\
-@seealso{pconnect, reval, psend, precv, sclose, parallel_generate_srp_data, select_sockets}\n\
-@end deftypefn")
-{
-  // Contrary to what is done in the client side function connect.cc,
-  // it is not necessarily always explicitely cared here for closing
-  // of sockets and freeing of allocated memory in cases of
-  // error. Since the processes exit in case of an internal error,
-  // there is sometimes no need to do this. Exceptions may return to
-  // the Octave prompt instead of exiting, but this is as good as
-  // exiting provided the server was started in a way that leads to
-  // exiting Octave as soon as the server returns.
-  //
-  // However, deallocation of anything which uses credentials has to
-  // be carefully provided here also, since the destructor of the
-  // ref-counted credentials must be called in the end to zero
-  // sensitive data before deallocation.
-
-  octave_value_list retval;
-
-  std::string fname ("pserver");
-
-  if (args.length () > 1)
-    {
-      print_usage ();
-
-      return retval;
-    }
-
-  // A negative integer might be sent as Octave data, and Octave
-  // doesn't care about coding of negative integers. (I know, there
-  // probably will never be a current C-compiler with something
-  // different than twos complement, but the C-standard allows for
-  // it.)
-  if (octave_parallel_stream::signed_int_rep ())
-    {
-      error ("This machine doesn't seem to use twos complement as negative integer representation. If you want this to be supported, please file a bug report.");
-
-      return retval;
-    }
-
-  struct utsname utsname_buf;
-  if (uname (&utsname_buf))
-    {
-      error ("error calling uname()");
-      return retval;
-    }
-  std::string hostname (utsname_buf.nodename);
-  std::string pidname ("/tmp/.octave-");
-  pidname = pidname + hostname + ".pid";
-
-  // default options
-  bool use_gnutls = true;
-  std::string cafile;
-
-  // get options, if any
-  if (args.length () == 1)
-    {
-      octave_scalar_map options;
-
-      CHECK_ERROR (options = args(0).scalar_map_value (), retval,
-                   "%s: could not convert second argument to scalar structure",
-                   fname.c_str ());
-
-      octave_value tmp;
-
-      // use TLS
-      tmp = options.contents ("use_tls");
-
-      if (tmp.is_defined ())
-        {
-          CHECK_ERROR (use_gnutls = tmp.bool_value (), retval,
-                       "%s: could not convert option 'use_tls' to bool",
-                       fname.c_str ());
-        }
-
-      // custom authentication file
-      tmp = options.contents ("auth_file");
-
-      if (tmp.is_defined ())
-        {
-          CHECK_ERROR (cafile = tmp.string_value (), retval,
-                       "%s: could not convert option 'auth_file' to string",
-                       fname.c_str ());
-        }
-    } // args.length () == 1
-
-  // check options integrity
-#ifndef HAVE_LIBGNUTLS
-  if (use_gnutls)
-    {
-      error ("TLS not available");
-      return retval;
-    }
-#endif
-  if (! use_gnutls && cafile.length ())
-    warning ("no TLS used, option 'auth_file' has no effect");
-
-  // initialize exit function
-  OCTAVE__FEVAL ("__pserver_exit__", octave_value (hostname), 0);
-
-  int tp;
-  if ((tp = fork ()))
-    {
-      if (tp == -1)
-        error ("could not fork");
-      return retval;
-    }
-
-  // register exit function
-  OCTAVE__FEVAL ("atexit", octave_value ("__pserver_exit__"), 0);
-
-  /* write pidfile and mark for deletion. */
-  if (check_and_write_pidfile (pidname.c_str (), getpid ()))
-    {
-      std::cerr << "octave: " << hostname.c_str ()
-                << ": can't write pidfile, server possibly already running"
-                << std::endl;
-      exit (1); // clean_up_and_exit (1);
-    }
-  mark_for_deletion (pidname.c_str ());
-  std::cout << pidname.c_str () << std::endl;
-
-  // avoid dumping octave_core if killed by a signal
-  OCTAVE__FEVAL ("sigterm_dumps_octave_core", octave_value (0), 0);
-  OCTAVE__FEVAL ("sighup_dumps_octave_core", octave_value (0), 0);
-
-  /* Redirect stdin and stdout to /dev/null. */
-  if (! freopen ("/dev/null", "r", stdin))
-    {
-      perror ("freopen");
-      exit (1); // clean_up_and_exit (1);
-    }
-  if (! freopen ("/dev/null", "w", stdout))
-    {
-      perror ("freopen");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  std::string errname ("/tmp/octave_error-");
-  errname = errname + hostname.c_str () + ".log";
-  struct stat fstat;
-  if (stat (errname.c_str (), &fstat) == 0)
-    {
-      std::string bakname ("/tmp/octave_error-");
-      bakname = bakname + hostname.c_str () + ".bak";
-      if (rename (errname.c_str (), bakname.c_str ()))
-        {
-          perror ("rename");
-          exit (1); // clean_up_and_exit (1);
-        }
-    }
-  if (! freopen (errname.c_str (), "w", stderr))
-    {
-      perror ("freopen");
-      exit (1); // clean_up_and_exit (1);
-    } 
-
-  struct addrinfo *ai, hints;
-
-  memset ((void *) &hints, 0, sizeof (hints));
-  hints.ai_family = AF_INET;
-  hints.ai_socktype = SOCK_STREAM;
-  hints.ai_protocol = 0;
-  hints.ai_flags = AI_PASSIVE;
-  if (getaddrinfo (NULL, "12502", &hints, &ai))
-    {
-      perror ("getaddrinfo");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  int sock = socket (PF_INET, SOCK_STREAM, 0);
-  if (sock == -1)
-    {
-      perror ("socket");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  if (bind (sock, ai->ai_addr, ai->ai_addrlen))
-    {
-      perror ("bind");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-
-  if (listen (sock, SOMAXCONN))
-    {
-      perror ("listen");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-
-  if (getaddrinfo (NULL, "12501", &hints, &ai))
-    {
-      perror ("getaddrinfo");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  int dsock = socket (PF_INET, SOCK_STREAM, 0);
-  if (dsock == -1)
-    {
-      perror ("socket");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  if (bind (dsock, ai->ai_addr, ai->ai_addrlen))
-    {
-      perror ("bind");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  if (listen (dsock, SOMAXCONN))
-    {
-      perror ("listen");
-      exit (1); // clean_up_and_exit (1);
-    }
-
-  freeaddrinfo (ai);
-
-  int server_no = -1; // for debugging
-  for(;;)
-    {
-      server_no++;
-      dsprintf ("server_no: %i, trying to accept command stream\n", server_no);
-      int asock = accept (sock, 0, 0);
-      if (asock == -1)
-        {
-          perror ("accept");
-          exit (1); // clean_up_and_exit (1);
-        }
-      dsprintf ("%i: accepted command stream\n", server_no);
-      /* Normal production daemon.  Fork, and have the child process
-         the connection.  The parent continues listening. */
-
-      // remove non-existing children from octave_child_list
-      OCTAVE_QUIT;
-
-      sigset_t nset, oset, dset;
-
-      BLOCK_CHILD (nset, oset);
-      BLOCK_SIGNAL (SIGTERM, nset, dset);
-      BLOCK_SIGNAL (SIGHUP, nset, dset);
-
-      // restores all signals to state before BLOCK_CHILD
-#define RESTORE_SIGNALS(ovar) UNBLOCK_CHILD(ovar)
-
-      int pid;
-      if ((pid = fork ()) == -1)
-        {
-          perror ("fork");
-          exit (1); // clean_up_and_exit (1);
-        }
-      else if (pid == 0) 
-        {
-          int tp;
-          if ((tp = fork ()))
-            {
-              if (tp == -1)
-                {
-                  perror ("fork");
-                  _exit (1);
-                }
-              else
-                _exit (0);
-            }
-
-          dsprintf ("%i: child after fork\n", server_no);
-          close (sock);
-          signal (SIGCHLD, SIG_DFL);
-          signal (SIGTERM, SIG_DFL);
-          signal (SIGQUIT, SIG_DFL);
-
-          RESTORE_SIGNALS (oset);
-
-#ifdef HAVE_LIBGNUTLS
-          struct __ccredguard
-          {
-            octave_parallel_gnutls_srp_client_credentials *__c;
-            __ccredguard (void) : __c (NULL) { }
-            ~__ccredguard (void) { if (__c && ! __c->check_ref ()) delete __c; }
-            octave_parallel_gnutls_srp_client_credentials *__get (void)
-            { return __c; }
-            void __set (octave_parallel_gnutls_srp_client_credentials *__ic)
-            { __c = __ic; }
-            void __release (void) { __c = NULL; }
-          }  __ccg;
-          octave_parallel_gnutls_srp_client_credentials *ccred;
-
-          struct __scredguard
-          {
-            octave_parallel_gnutls_srp_server_credentials *__c;
-            __scredguard (void) : __c (NULL) { }
-            ~__scredguard (void) { if (__c && ! __c->check_ref ()) delete __c; }
-            octave_parallel_gnutls_srp_server_credentials *__get (void)
-            { return __c; }
-            void __set (octave_parallel_gnutls_srp_server_credentials *__ic)
-            { __c = __ic; }
-            void __release (void) { __c = NULL; }
-          }  __scg;
-          octave_parallel_gnutls_srp_server_credentials *scred;
-
-          if (use_gnutls)
-            {
-              gnutls_global_init (); 
-#ifdef HAVE_LIBGNUTLS_EXTRA
-              gnutls_global_init_extra ();  // for SRP
-              parallel_gnutls_set_mem_functions ();
-#endif
-
-              dsprintf ("%i: after initializing gnutls\n", server_no);
-
-              // generate credentials
-              if (! cafile.length ())
-                {
-#ifdef HAVE_OCTAVE_CONFIG_FCNS
-                  std::string octave_home = octave::config::octave_home ();
-#else
-                  extern std::string Voctave_home;
-                  std::string octave_home = Voctave_home;
-#endif
-                  cafile = octave_home +
-                    OCTAVE__SYS__FILE_OPS::dir_sep_str () + "share" +
-                    OCTAVE__SYS__FILE_OPS::dir_sep_str () + "octave" +
-                    OCTAVE__SYS__FILE_OPS::dir_sep_str () +
-                    "parallel-srp-data" +
-                    OCTAVE__SYS__FILE_OPS::dir_sep_str () + "server" +
-                    OCTAVE__SYS__FILE_OPS::dir_sep_str () + "passwd";
-                  if (assert_file (cafile))
-                    {
-                      octave_value_list f_args (1);
-                      f_args(0) = octave_value ("prefix");
-                      octave_value_list f_ret;
-                      CHECK_ERROR_EXIT1 (f_ret = OCTAVE__FEVAL ("pkg", f_args, 1),
-                                         "%s: could not get prefix from pkg",
-                                         fname.c_str ());
-                      CHECK_ERROR_EXIT1 (cafile = f_ret(0).string_value (),
-                                         "%s: could not convert output of pkg ('prefix') to string)",
-                                         fname.c_str ());
-                      cafile = cafile + OCTAVE__SYS__FILE_OPS::dir_sep_str () +
-                        "parallel-srp-data" +
-                        OCTAVE__SYS__FILE_OPS::dir_sep_str () + "server" +
-                        OCTAVE__SYS__FILE_OPS::dir_sep_str () + "passwd";
-                      if (assert_file (cafile))
-                        {
-                          error ("%s: no regular file found at default password file paths",
-                                 fname.c_str ());
-                          _exit (1);
-                        }
-                    }
-                }
-              else if (assert_file (cafile))
-                {
-                  error ("%s: no regular file found at password file path given by user",
-                         fname.c_str ());
-                  _exit (1);
-                }
-              __scg.__set (scred =
-                           new octave_parallel_gnutls_srp_server_credentials
-                           (cafile));
-              dsprintf ("%i: after generating credentials\n", server_no);
-              if (! __scg.__get ()->check_cred ())
-                {
-                  error ("%s: could not create credentials",
-                         fname.c_str ());
-                  _exit (1);
-                }
-            }
-#endif // HAVE_LIBGNUTLS
-
-          // determine own number of usable processor cores
-          uint32_t nproc = num_processors (NPROC_CURRENT);
-
-          // The servers command stream will not be inserted into a
-          // connection object.
-          octave_parallel_streambuf *cmd_strb;
-#ifdef HAVE_LIBGNUTLS
-          if (use_gnutls)
-            {
-              dsprintf ("%i: will generate gnutls streambuf\n", server_no);
-              cmd_strb = new octave_parallel_gnutls_streambuf
-                (asock, scred, true);
-              __scg.__release ();
-              dsprintf ("%i: generated gnutls streambuf\n", server_no);
-            }
-          else
-#endif
-            cmd_strb = new octave_parallel_socket_streambuf (asock, true);
-          octave_parallel_stream cmd_str (cmd_strb);
-          if (! cmd_str.good ())
-            {
-              error ("could not create command stream");
-              _exit (1);
-            }
-
-          uint32_t nhosts;
-          cmd_str.network_recv_4byteint (nhosts);
-          dsprintf ("%i: received nhosts (%i), good: %i\n", server_no, nhosts, cmd_str.good ());
-
-          cmd_str.network_send_4byteint (nproc, true);
-          dsprintf ("%i: sent nproc (%u), good: %i\n", server_no, nproc, cmd_str.good ());
-
-          uint32_t me;
-          cmd_str.network_recv_4byteint (me);
-          dsprintf ("%i: received me (%i), good: %i\n", server_no, me, cmd_str.good ());
-
-          std::string uuid;
-          cmd_str.network_recv_string (uuid);
-          dsprintf ("%i: received uuid (%s), good: %i\n", server_no, uuid.c_str (), cmd_str.good ());
-
-          if (! cmd_str.good ()) // check before using the received 'nhosts'
-            {
-              error ("communication error in initialization");
-              _exit (1);
-            }
-          Array<std::string> hosts (dim_vector (nhosts, 1));
-          for (uint32_t i = 0; i < nhosts; i++)
-            {
-            cmd_str.network_recv_string (hosts(i));
-            dsprintf ("%i: received hostname no %i (%s)\n", server_no, i, hosts(i).c_str ());
-            }
-
-          dsprintf ("will now change name of error file\n");
-          errname = std::string ("/tmp/octave_error-") + hostname.c_str () +
-            "_" + uuid.c_str () + ".log";
-          if (stat (errname.c_str (), &fstat) == 0)
-            {
-              std::string bakname ("/tmp/octave_error-");
-              bakname = bakname + hostname.c_str () +
-                "_" + uuid.c_str () + ".bak";
-              if (rename (errname.c_str (), bakname.c_str ()))
-                {
-                  perror ("rename");
-                  _exit (1);
-                }
-            }
-          if (! freopen (errname.c_str (), "w", stderr))
-            {
-              perror ("freopen");
-              _exit (1);
-            }
-
-          std::string directory;
-          cmd_str.network_recv_string (directory);
-          dsprintf ("%i: received directory (%s)\n", server_no, directory.c_str ());
-
-#define BUFLEN 1024
-          struct __pwguard
-          {
-            char *__pw;
-            int __len;
-            __pwguard (int __alen) : __pw (new char[__alen]), __len (__alen) { }
-            void __free (void)
-            {
-              if (__pw)
-                {
-                  memset ((void *) __pw, 0, __len);
-                  delete [] __pw;
-                  __pw = NULL;
-                }
-            }
-            ~__pwguard (void) { __free (); }
-            char *__get (void) { return __pw; }
-          } __pwg (BUFLEN);
-          if (use_gnutls)
-            {
-              cmd_str.network_recv_string (__pwg.__get (), BUFLEN);
-              if (me == nhosts) // we won't need it 
-                __pwg.__free ();
-              dsprintf ("%i: received password (%s)\n", server_no, __pwg.__get ());
-            }
-
-          if (! cmd_str.good ())
-            {
-              error ("communication error in initialization");
-              _exit (1);
-            }
-
-          // client may shut down before starting data connections (if
-          // it was unable to establish all command connections)
-          struct pollfd pfd[2];
-          pfd[0].fd = asock;
-          pfd[0].events = POLLIN | POLLHUP; // POLLHUP meaningless here?
-          pfd[0].revents = 0;
-          pfd[1].fd = dsock;
-          pfd[1].events = POLLIN; // will be set if accept is possible
-          pfd[1].revents = 0;
-          if (poll (pfd, 2, -1) == -1)
-            {
-              error ("error in poll()");
-              _exit (1);
-            }
-          if (pfd[0].revents)
-            {
-              error ("unexpected event at command socket");
-              _exit (1);
-            }
-
-          octave_parallel_network *network;
-          struct __netwguard
-          {
-            octave_parallel_network *__n;
-            __netwguard (octave_parallel_network *__an) : __n (__an)
-            { __n->get_ref (); }
-            ~__netwguard (void) { if (__n->release_ref () <= 0) delete __n; }
-          } __ng (network = new octave_parallel_network (nhosts + 1));
-
-          for (uint32_t i = 0; i < me; i++)
-            {
-              //      recv;
-
-              dsprintf ("%i: trying to accept data connection, %i\n", server_no, i);
-              int not_connected = 1;
-              for (int j = 0; j < N_CONNECT_RETRIES; j++)
-                {
-                  struct sockaddr_in rem_addr;
-                  socklen_t addrlen = sizeof (rem_addr);
-                  int adsock = accept (dsock, (sockaddr *) &rem_addr, &addrlen);
-                  if (adsock == -1)
-                    {
-                      perror ("accept, data stream");
-                      _exit (1);
-                    }
-                  dsprintf ("server %i, host %i, retry %i, accept successful\n", server_no, i, j);
-                  if (addrlen > sizeof (rem_addr))
-                    {
-                      perror ("accept, data stream, address buffer to short");
-                      _exit (1);
-                    }
-                  struct __sockguard
-                  {
-                    __sockguard (int __isock) { __sock = __isock; }
-                    ~__sockguard (void) { if (__sock > -1) close (__sock); }
-                    void __release (void) { __sock = -1; }
-                    int __sock;
-                  } __sockg (adsock);
-#define HOSTNAMEBUFLEN 257
-                  char peername[HOSTNAMEBUFLEN];
-                  if (getnameinfo ((sockaddr *) &rem_addr, addrlen,
-                                   (char *) peername, HOSTNAMEBUFLEN,
-                                   NULL, 0, 0))
-                    {
-                      error ("getnameinfo returned an error");
-                      _exit (1);
-                    }
-
-                  octave_parallel_connection *conn =
-                    new octave_parallel_connection
-                    (peername, true, uuid.c_str ());
-
-                  // you don't know the position to insert the
-                  // connection (protecting it) yet, an exception may
-                  // be thrown before you know it
-                  struct __connguard
-                  {
-                    __connguard (octave_parallel_connection *__ipt)
-                    { __pt = __ipt; }
-                    ~__connguard (void) { if (__pt) delete __pt; }
-                    void __set (octave_parallel_connection *__ipt)
-                    { __pt = __ipt; }
-                    octave_parallel_connection *__pt;
-                    void __release (void) { __pt = NULL; }
-                  } __conng (conn);
-
-#ifdef HAVE_LIBGNUTLS
-                  if (use_gnutls)
-                    {
-                    conn->insert_data_stream
-                      (new octave_parallel_stream
-                       (new octave_parallel_gnutls_streambuf
-                        (adsock, scred, true)));
-                    dsprintf ("server %i, host %i, retry %i, generated gnutls streambuf\n", server_no, i, j);
-                    }
-                  else
-#endif
-                    conn->insert_data_stream
-                      (new octave_parallel_stream
-                       (new octave_parallel_socket_streambuf (adsock, true)));
-
-                  __sockg.__release ();
-
-                  if (! conn->get_data_stream ()->good ())
-                    {
-                      error ("could not create data stream to %s", peername);
-                      _exit (1);
-                    }
-
-                  std::string duuid;
-                  conn->get_data_stream ()->network_recv_string (duuid);
-                  dsprintf ("server %i, host %i, retry %i, received uuid (%s)\n", server_no, i, j, duuid.c_str ());
-                 
-                  uint32_t host_n;
-                  conn->get_data_stream ()->network_recv_4byteint (host_n);
-                  dsprintf ("server %i, host %i, retry %i, received host_n (%i)\n", server_no, i, j, host_n);
-
-                  if (! conn->get_data_stream ()->good ())
-                    {
-                      error ("communication error in initialization");
-                      _exit (1);
-                    }
-
-                  if (uuid.compare (duuid))
-                    {
-                      // a different call to 'connect', i.e. a different network
-                      conn->get_data_stream ()->network_send_4byteint (-1);
-                      if (conn->delete_data_stream ())
-                        {
-                          error ("could not delete data stream");
-                          _exit (1);
-                        }
-                      dsprintf ("server %i, host %i, retry %i, sent result -1\n", server_no, i, j);
-                      sleep (1);
-                    }
-                  else if (me <= host_n || network->is_connection (host_n))
-                    {
-                      // we should never get here (since duuid == uuid)
-                      conn->get_data_stream ()->network_send_4byteint (-2);
-                      error ("server %i, host %i, retry %i, internal error, unexpected host id %i, is_connection(host id): %i", server_no, i, j, host_n,
-                             network->is_connection (host_n));
-                      _exit (1);
-                    }
-                  else
-                    {
-                      conn->get_data_stream ()->network_send_4byteint (0);
-                      int err = conn->connection_read_header ();
-                      minimal_write_header
-                        (conn->get_data_stream ()->get_ostream ());
-                      if (err || ! conn->get_data_stream ()->good ())
-                        {
-                          error ("communication error in initialization");
-                          _exit (1);
-                        }
-                      network->insert_connection (conn, host_n);
-                      __conng.__release ();
-                      not_connected = 0;
-                      dsprintf ("server %i, host %i, retry %i, good result sent, header read, header written and data stream good, breaking\n", server_no, i, j);
-                      break;
-                    }
-                }
-              if (not_connected)
-                {
-                  error ("maximum number of connect retries exceeded");
-                  _exit (-1);
-                }
-            }
-
-          close (dsock);
-
-
-          // a pseudo-connection, representing the own node in the network
-          octave_parallel_connection *conn =
-            new octave_parallel_connection (true, uuid.c_str ());
-
-          network->insert_connection (conn, me);
-          dsprintf ("server %i inserted pseudoconnection at %i\n", server_no, me);
-
-          // store number of available processor cores at the own
-          // machine, although this is not necessary (but we have this
-          // information here ...)
-          conn->set_nproc (nproc);
-
-#ifdef HAVE_LIBGNUTLS
-          if (use_gnutls && me < nhosts)
-            {
-              const char *username =
-                static_cast<octave_parallel_gnutls_streambuf*>(cmd_strb)->
-                server_get_username ();
-              dsprintf ("server %i determined username %s from command stream, will now allocate client credentials (for data connections) with this username and password %s\n", server_no, username, __pwg.__get ());
-
-              __ccg.__set (ccred =
-                           new octave_parallel_gnutls_srp_client_credentials
-                           (username, __pwg.__get ()));
-            }
-#endif
-
-
-          for (uint32_t i = me + 1; i <= nhosts; i++)
-            {
-              // connect;
-              dsprintf ("connect, server %i, host %i\n", server_no, i);
-
-              struct addrinfo *ai = NULL, hints;
-              memset ((void *) &hints, 0, sizeof (hints));
-              hints.ai_family = AF_INET;
-              hints.ai_socktype = SOCK_STREAM;
-              hints.ai_protocol = 0;
-              hints.ai_flags = 0;
-              if (getaddrinfo (hosts(i - 1).c_str (), "12501", &hints, &ai))
-                {
-                  error ("getaddrinfo returned an error");
-                  _exit (1);
-                }
-              struct __aiguard
-              {
-                __aiguard (struct addrinfo *__iai) { __ai = __iai; }
-                ~__aiguard (void) { if (__ai) freeaddrinfo (__ai); }
-                struct addrinfo *__ai;
-              } __aig (ai);
-
-              int not_connected = 1;
-              for (int j = 0; j < N_CONNECT_RETRIES; j++)
-                {
-                  int dsock = socket (PF_INET, SOCK_STREAM, 0);
-                  if (dsock == -1)
-                    {
-                      perror ("socket");
-                      _exit (1);
-                    }
-                  struct __sockguard
-                  {
-                    __sockguard (int __isock) { __sock = __isock; }
-                    ~__sockguard (void) { if (__sock > -1) close (__sock); }
-                    void __release (void) { __sock = -1; }
-                    int __sock;
-                  } __sockg (dsock);
-
-                  if (connect (dsock, ai->ai_addr, ai->ai_addrlen) == 0)
-                    {
-                      dsprintf ("connect, server %i, host %i, retry %i, connect succesful\n", server_no, i, j);
-                      octave_parallel_connection *conn =
-                        new octave_parallel_connection
-                        (hosts(i - 1).c_str (), true, uuid.c_str ());
-                      network->insert_connection (conn, i);
-
-#ifdef HAVE_LIBGNUTLS
-                      if (use_gnutls)
-                        {
-                          conn->insert_data_stream
-                            (new octave_parallel_stream
-                             (new octave_parallel_gnutls_streambuf
-                              (dsock, ccred, false)));
-                          __ccg.__release ();
-                          dsprintf ("connect, server %i, host %i, retry %i, generated gnutls streambuf\n", server_no, i, j);
-                        }
-                      else
-#endif
-                        conn->insert_data_stream
-                          (new octave_parallel_stream
-                           (new octave_parallel_socket_streambuf (dsock, false)));
-                      __sockg.__release ();
-                      if (! conn->get_data_stream ()->good ())
-                        {
-                          error ("could not create data stream to %s",
-                                 hosts(i - 1).c_str ());
-                          _exit (1);
-                        }
-
-                      conn->get_data_stream ()->
-                        network_send_string (uuid.c_str ());
-                      dsprintf ("connect, server %i, host %i, retry %i, uuid written (%s)\n", server_no, i, j, uuid.c_str ());
-
-                      conn->get_data_stream ()->network_send_4byteint (me,
-                                                                       true);
-                      dsprintf ("connect, server %i, host %i, retry %i, 'me' written (%i)\n", server_no, i, j, me);
-
-                      int32_t res;
-                      conn->get_data_stream ()->network_recv_4byteint (res);
-
-                      if (! conn->get_data_stream ()->good ())
-                        {
-                          error ("communication error in initialization");
-                          _exit (1);
-                        }
-
-                      if (res == -1)
-                        {
-                          if (conn->delete_data_stream ())
-                            {
-                              error ("could not delete data stream");
-                              _exit (1);
-                            }
-
-                          dsprintf ("connect, server %i, host %i, retry %i, sleeping after bad result\n", server_no, i, j);
-                          usleep (5000);
-                        }
-                      else if (res)
-                        {
-                          error ("unexpected error in remote server");
-                          _exit (1);
-                        }
-                      else
-                        {
-                          minimal_write_header
-                            (conn->get_data_stream ()->get_ostream ());
-                          if (conn->connection_read_header () ||
-                              ! conn->get_data_stream ()->good ())
-                            {
-                              error ("communication error in initialization");
-                              _exit (1);
-                            }
-                          not_connected = 0;
-                          dsprintf ("connect, server %i, host %i, retry %i, good result read, header written and read and datastream good, breaking\n", server_no, i, j);
-                           break; 
-                        }
-                    }
-                  else if (errno != ECONNREFUSED && errno != EINTR)
-                    {
-                      perror ("connect");
-                      break;
-                    }
-                  else
-                    usleep (5000);
-                }
-
-              if (not_connected)
-                {
-                  error ("unable to connect to %s", hosts(i - 1).c_str ());
-                  _exit (1);
-                }
-            }
-
-          octave_parallel_connections *conns = new octave_parallel_connections
-            (network, uuid.c_str (),
-             true);
-          octave_value sockets (conns);
-
-          __pwg.__free ();
-
-#ifdef HAVE_OCTAVE_INTERPRETER_H
-          OCTAVE__INTERPRETER::the_interpreter () -> interactive (false);
-#else
-          interactive = false;
-#endif
-
-          // install 'sockets' as Octave variable
-          OCTAVE__INTERPRETER__SYMBOL_TABLE__ASSIGN ("sockets", sockets);
-          dsprintf ("'sockets' installed\n");
-
-          int cd_ok = octave_env::chdir (directory.c_str ());
-          if (! cd_ok)
-            {
-            octave_env::chdir ("/tmp");
-            dsprintf ("performed chdir to /tmp\n");
-            }
-          else
-            dsprintf ("performed chdir to %s\n", directory.c_str ());
-
-          dsprintf ("calling function reval_loop\n");
-          reval_loop (cmd_str); // does not return
-        }
-
-      // parent
-
-      waitpid (pid, NULL, 0); // child with pid has forked another child
-
-      // FIXME: forgotten how this is organized in Octave, find it out
-      // again and at least make a comment which better explains it.
-      OCTAVE_CHILD_LIST insert (pid, pserver_child_event_handler);
-
-      RESTORE_SIGNALS (oset);
-
-      close (asock);
-    }
-
-  // This code is currently not reached since the server parent
-  // process can only be killed by a signal.
-  close (sock);
-  exit (1); // clean_up_and_exit (1);
-  // Silence compiler warning.
-  exit (0);
-}
diff -urN parallel-3.1.3/src/p-sighandler.h octave-parallel/src/p-sighandler.h
--- parallel-3.1.3/src/p-sighandler.h	2018-08-03 09:41:42.566478128 +0200
+++ octave-parallel/src/p-sighandler.h	2019-08-02 12:43:39.652207924 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/reval.cc octave-parallel/src/reval.cc
--- parallel-3.1.3/src/reval.cc	2018-08-03 09:41:42.570478207 +0200
+++ octave-parallel/src/reval.cc	2019-08-02 12:43:39.655207869 +0200
@@ -5,7 +5,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/sclose.cc octave-parallel/src/sclose.cc
--- parallel-3.1.3/src/sclose.cc	2018-08-03 09:41:42.574478286 +0200
+++ octave-parallel/src/sclose.cc	2019-08-02 12:43:39.656207851 +0200
@@ -5,7 +5,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
diff -urN parallel-3.1.3/src/select_sockets.cc octave-parallel/src/select_sockets.cc
--- parallel-3.1.3/src/select_sockets.cc	2018-08-03 09:41:42.574478286 +0200
+++ octave-parallel/src/select_sockets.cc	2019-08-02 12:43:39.657207833 +0200
@@ -4,7 +4,7 @@
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; either version 3 of the License, or
 (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,