From 67902c3c1ebcc3d39e2fba44f66726f16489edba Mon Sep 17 00:00:00 2001 From: Eshel Yaron Date: Tue, 15 Nov 2022 23:45:02 +0200 Subject: [PATCH] Start the top-level TCP server just-in-time * sweeprolog.el (sweeprolog-init): do not start TCP server unconditionally (sweeprolog-top-level): start it here instead, on demand. * sweep.pl (sweep_top_level_server/2): wait for TCP server thread to start before returning control to Emacs. * README.org (The Prolog Top-Level): add implementation note. --- README.org | 15 ++++++++++++++- sweep.pl | 10 ++++++++-- sweeprolog.el | 5 +++-- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/README.org b/README.org index 0f1c212..62aa707 100644 --- a/README.org +++ b/README.org @@ -1107,7 +1107,7 @@ definition or invocation in a ~sweeprolog-mode~, that predicate is set as the default selection and can be described by simply typing ~RET~ in response to the prompt. -* The Prolog top-level +* The Prolog Top-Level :PROPERTIES: :CUSTOM_ID: prolog-top-level :DESCRIPTION: Executing Prolog queries in a REPL-like interface @@ -1128,6 +1128,19 @@ common mode used in Emacs REPL interfaces. As a result, the top-level buffer inherits the features present in other =comint-mode= derivatives, most of which are described in [[info:emacs#Shell Mode][the Emacs manual]]. +Each top-level buffer is connected to distinct Prolog thread running +in the same process as Emacs and the main Prolog runtime. In the +current implementation, top-level buffers communicate with their +corresponding threads via local TCP connections. On the first +invocation of ~sweeprolog-top-level~, ~sweep~ creates a TCP server socket +bound to a random port to accept incoming connections from top-level +buffers. The TCP server only accepts connections from the local +machine, but note that _other users on the same host_ may be able to +connect to the TCP server socket and _get a Prolog top-level_. This may +pose a security problem when sharing a host with entrusted users, +hence ~sweeprolog-top-level~ _should not be used on shared machines_. +This is the only ~sweep~ feature that should be avoided in such cases. + ** Multiple top-levels :PROPERTIES: :CUSTOM_ID: multiple-top-levels diff --git a/sweep.pl b/sweep.pl index 233c7ef..7d1032e 100644 --- a/sweep.pl +++ b/sweep.pl @@ -607,7 +607,8 @@ sweep_top_level_server(_, Port) :- tcp_setopt(ServerSocket, reuseaddr), tcp_bind(ServerSocket, Port), tcp_listen(ServerSocket, 5), - thread_create(sweep_top_level_server_loop(ServerSocket), T, + thread_self(Self), + thread_create(sweep_top_level_server_start(Self, ServerSocket), T, [ alias(sweep_top_level_server) ]), at_halt(( is_thread(T), @@ -615,7 +616,12 @@ sweep_top_level_server(_, Port) :- -> thread_signal(T, thread_exit(0)), thread_join(T, _) ; true - )). + )), + thread_get_message(sweep_top_level_server_started). + +sweep_top_level_server_start(Caller, ServerSocket) :- + thread_send_message(Caller, sweep_top_level_server_started), + sweep_top_level_server_loop(ServerSocket). sweep_top_level_server_loop(ServerSocket) :- thread_get_message(Message), diff --git a/sweeprolog.el b/sweeprolog.el index bc4a46f..87dfcc3 100644 --- a/sweeprolog.el +++ b/sweeprolog.el @@ -524,8 +524,7 @@ extra initialization arguments." (cons (or sweeprolog-swipl-path (executable-find "swipl")) (append sweeprolog-init-args args))) (setq sweeprolog--initialized t) - (sweeprolog-setup-message-hook) - (sweeprolog-start-prolog-server))) + (sweeprolog-setup-message-hook))) (defun sweeprolog-restart (&rest args) "Restart the embedded Prolog runtime. @@ -2222,6 +2221,8 @@ Interactively, a prefix arg means to prompt for BUFFER." (with-current-buffer buf (unless (eq major-mode 'sweeprolog-top-level-mode) (sweeprolog-top-level-mode))) + (unless sweeprolog-prolog-server-port + (sweeprolog-start-prolog-server)) (unless (sweeprolog--query-once "sweep" "sweep_accept_top_level_client" (buffer-name buf)) (error "Failed to create new top-level!")) -- 2.39.2