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,