]> git.eshelyaron.com Git - sweep.git/commitdiff
ENHANCED: Support pty top-level communication instead of TCP
authorEshel Yaron <me@eshelyaron.com>
Thu, 14 Sep 2023 16:28:16 +0000 (18:28 +0200)
committerEshel Yaron <me@eshelyaron.com>
Thu, 14 Sep 2023 18:56:07 +0000 (20:56 +0200)
Add the ability for top-level buffers to communicate with their
backing threads via pty instead of a local TCP connection.  This is
controlled by a new user option, enabled by default on systems where
Emacs can creates a pty.

* sweep.pl (sweep_top_level_start_pty/2): New predicate.
* sweeprolog.el (sweeprolog-top-level-use-pty): New user option.
(sweeprolog-top-level-buffer): Use it.
* sweep.texi (The Prolog Top-level): Document it.

sweep.pl
sweep.texi
sweeprolog.el

index d9d10e98987176a4d83fb6eeb1e6588de411a924..efffccb5974727d6ada9ff18cc2c44081cfcb592 100644 (file)
--- a/sweep.pl
+++ b/sweep.pl
@@ -95,7 +95,8 @@
             sweep_functors_collection/2,
             sweep_compound_functors_collection/2,
             sweep_term_variable_names/2,
-            sweep_goal_may_cut/2
+            sweep_goal_may_cut/2,
+            sweep_top_level_start_pty/2
           ]).
 
 :- use_module(library(pldoc)).
@@ -772,6 +773,16 @@ write_sweep_module_location :-
     format('M ~w~n', Path).
 :- endif.
 
+sweep_top_level_start_pty([Name|Buffer], _) :-
+    thread_create(sweep_top_level_pty_client(Name), T, [detached(true)]),
+    thread_property(T, id(Id)),
+    asserta(sweep_top_level_thread_buffer(Id, Buffer)).
+
+sweep_top_level_pty_client(Name) :-
+    open(Name, read, InStream, [eof_action(reset)]),
+    open(Name, write, OutStream),
+    sweep_top_level_client(InStream, OutStream, ip(127,0,0,1)).
+
 sweep_top_level_server(_, Port) :-
     tcp_socket(ServerSocket),
     tcp_setopt(ServerSocket, reuseaddr),
index f8d427434e184f9a5121685d5a93188a0209385b..4aa657db82d2625d77ee816652a441862d38f291 100644 (file)
@@ -2631,19 +2631,37 @@ top-level buffer inherits the features present in other
 @code{comint-mode} derivatives, most of which are described in
 @ref{Shell Mode,,,emacs,}.
 
-The top-level buffer is connected to a 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
-@code{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 untrusted users,
-hence @code{sweeprolog-top-level} should not be used on shared
-machines.  This is the only Sweep command that you want to avoid in
-such cases.
+@cindex top-level communication
+@cindex communication, top-level
+Top-level buffers are backed by Prolog threads that run in the same
+process as Emacs and the main Prolog runtime.  On Unix systems,
+top-levels communicate with their corresponding threads via a
+pseudo-terminal device (@dfn{pty}).  Alternatively, Sweep top-level
+buffers can communicate with their threads via a local TCP connection.
+You can force Sweep to use TCP instead of a pty on Unix systems by
+customizing the user option @code{sweeprolog-top-level-use-pty} to
+@code{nil}.
+
+@defopt sweeprolog-top-level-use-pty
+Whether to use pty for top-level communication.  If this is non-nil,
+Sweep top-level buffers communicate with their top-level threads via a
+pty, otherwise they use a local TCP connection.
+@end defopt
+
+@code{sweeprolog-top-level-use-pty} is on by default on systems where
+Emacs can use a pty.  On other systems, such as MS Windows, or when
+otherwise @code{sweeprolog-top-level-use-pty} is set to @code{nil},
+Sweep creates a TCP server socket bound to a random port to accept
+incoming connections from top-level buffers.  Sweep only starts this
+TCP server socket when you first invoke of
+@code{sweeprolog-top-level}, so there are no listening sockets before
+you actually use the top-level.  The TCP server only accepts
+connections from the local machine, but note that other users on the
+same host might be able to connect to the TCP server socket and get a
+Prolog top-level.  This may be a security concern if you are sharing a
+host with untrusted users, so you should be careful about using
+@code{sweeprolog-top-level} with @code{sweeprolog-top-level-use-pty}
+set to @code{nil} on shared machines.
 
 @menu
 * Multiple Top-levels::          Creating and handling multiple Prolog top-level buffers
index 3941d816b97aaaa7491c805410f2ec9c65b9785e..1c6d1723f6214cd30f847475e898cbccf849011d 100644 (file)
@@ -3131,6 +3131,12 @@ function with PROC and MSG."
                           #'sweeprolog-top-level-sentinel)
     (add-hook 'kill-buffer-hook #'comint-write-input-ring nil t)))
 
+(defcustom sweeprolog-top-level-use-pty
+  (not (memq system-type '(ms-dos windows-nt)))
+  "Whether to communicate with top-levels using pseudo-terminal (\"pty\").
+
+By default, this is t on systems where Emacs can use a pty.")
+
 (defun sweeprolog-top-level-buffer (&optional name)
   "Return a Prolog top-level buffer named NAME.
 
@@ -3138,20 +3144,27 @@ If NAME is nil, use the default name \"*sweeprolog-top-level*\".
 
 If the buffer already exists, ensure it is associated with a live
 top-level."
-  (unless sweeprolog-prolog-server-port
-    (sweeprolog-start-prolog-server))
   (let ((buf (get-buffer-create (or name "*sweeprolog-top-level*"))))
     (unless (process-live-p (get-buffer-process buf))
       (with-current-buffer buf
         (unless (derived-mode-p 'sweeprolog-top-level-mode)
           (sweeprolog-top-level-mode)))
-      (unless (sweeprolog--query-once "sweep" "sweep_accept_top_level_client"
-                                      (buffer-name buf))
-        (error "Failed to create new top-level!"))
-      (make-comint-in-buffer "sweeprolog-top-level"
-                             buf
-                             (cons "localhost"
-                                   sweeprolog-prolog-server-port))
+      (if sweeprolog-top-level-use-pty
+          (progn
+            (make-comint-in-buffer "sweeprolog-top-level" buf nil)
+            (process-send-eof (get-buffer-process buf))
+            (sweeprolog--query-once "sweep" "sweep_top_level_start_pty"
+                                    (cons (process-tty-name
+                                           (get-buffer-process buf))
+                                          (buffer-name buf))))
+        (unless sweeprolog-prolog-server-port
+          (sweeprolog-start-prolog-server))
+        (sweeprolog--query-once "sweep" "sweep_accept_top_level_client"
+                                (buffer-name buf))
+        (make-comint-in-buffer "sweeprolog-top-level"
+                               buf
+                               (cons "localhost"
+                                     sweeprolog-prolog-server-port)))
       (unless comint-last-prompt
         (accept-process-output (get-buffer-process buf) 1))
       (sweeprolog-top-level-setup-history buf)