]> git.eshelyaron.com Git - emacs.git/commitdiff
Reuse process in erc-server-delayed-check-reconnect
authorF. Jason Park <jp@neverwas.me>
Tue, 24 Dec 2024 06:21:34 +0000 (22:21 -0800)
committerEshel Yaron <me@eshelyaron.com>
Sat, 4 Jan 2025 20:22:05 +0000 (21:22 +0100)
* doc/misc/erc.texi (Integrations): Set `erc-server-reconnect-function'
to `erc-server-delayed-check-reconnect' in SOCKS example, and add
definition for `erc-open-socks-tls-stream'.  Mention possible
inaccuracies related to error detection with certain reconnect
strategies.
* lisp/erc/erc-backend.el (erc-server--reconnect-opened): New function.
(erc-server-delayed-check-reconnect): Attempt to reuse process if server
sends a complete PONG, and attempt to accommodate connectors that set
:nowait to nil.
(erc--server-delayed-check-connectors): Remove variable.
(erc-server-prefer-check-reconnect): Inline what was the internal
variable `erc--server-delayed-check-connectors' because it's no longer
used in unit tests.  Add `erc-open-socks-tls-stream' to the set of
connector functions thought to be compatible with the "check" reconnect
strategy.
* test/lisp/erc/erc-scenarios-base-auto-recon.el
(erc-scenarios-base-auto-recon-no-proto): Adapt to expect "reuse" behavior.
* test/lisp/erc/resources/base/reconnect/ping-pong.eld: Delete unused file.
* test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld:
Capture PING cookie to send back to client.
* test/lisp/erc/resources/erc-d/resources/proxy-solo.eld: Delete unused
file.  (Bug#62044)

(cherry picked from commit f5ebe47ba7723919f09adf8f28d896cfa8757842)

doc/misc/erc.texi
lisp/erc/erc-backend.el
test/lisp/erc/erc-scenarios-base-auto-recon.el
test/lisp/erc/resources/base/reconnect/ping-pong.eld [deleted file]
test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld
test/lisp/erc/resources/erc-d/resources/proxy-solo.eld [deleted file]

index aa62c1b3274cf3e3ff72f10eb472863fe2afbcaa..eaf3958ba866cf7f17098dc4683fbbacc33861ab 100644 (file)
@@ -1667,6 +1667,8 @@ shown in the following example:
         (socks-server '("tor" "localhost" 9050 5)))
     (apply #'erc-open-socks-tls-stream args)))
 
+(setopt erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
+
 (let* ((erc-modules (cons 'sasl erc-modules))
        (erc-sasl-mechanism 'external)
        (erc-server-connect-function #'my-erc-open-socks-tls-stream))
@@ -1687,6 +1689,18 @@ with ERC exclusively, you can just set those options and variables
 globally and bind @code{erc-server-connect-function} to
 @code{erc-open-socks-tls-stream} instead.
 
+@defun erc-open-socks-tls-stream
+The default TLS @dfn{connector} for @acronym{SOCKS} connections.
+Compatible with option @code{erc-server-connect-function}.  Be aware
+that if used in conjunction with certain values of
+@code{erc-server-reconnect-function} (such as
+@code{erc-server-prefer-check-reconnect}, currently the default
+@dfn{reconnector}, or @code{erc-server-delayed-check-reconnect}, the
+more specialized workhorse it defers to), this function may cause ERC to
+misreport proxy-related failures as routine lapses in internet
+connectivity.
+@end defun
+
 @node auth-source
 @subsection auth-source
 @cindex auth-source
index a5153df6fc3df681ac050b9704d45c0d3e30d97a..a052c35a4baa59386f8214253ce7725ae6eb8f3b 100644 (file)
@@ -830,6 +830,13 @@ Make sure you are in an ERC buffer when running this."
     (with-current-buffer buffer
       (erc-server-reconnect))))
 
+(defun erc-server--reconnect-opened (buffer process)
+  "Reconnect session for server BUFFER using open PROCESS."
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (let ((erc-session-connector (lambda (&rest _) process)))
+        (erc-server-reconnect)))))
+
 (defvar-local erc--server-reconnect-timeout nil)
 (defvar-local erc--server-reconnect-timeout-check 10)
 (defvar-local erc--server-reconnect-timeout-scale-function
@@ -845,7 +852,13 @@ Make sure you are in an ERC buffer when running this."
 
 (defun erc-server-delayed-check-reconnect (buffer)
   "Wait for internet connectivity before trying to reconnect.
-Expect BUFFER to be the server buffer for the current connection."
+Use server BUFFER's cached session info to reestablish the logical
+connection at the IRC protocol level.  Do this by probing for a
+successful response to a PING before commencing with \"connection
+registration\".  Do not distinguish between configuration problems and
+the absence of service.  For example, expect users of proxy-based
+connectors, like `erc-open-socks-tls-stream', to ensure their setup
+works before choosing this function as their reconnector."
   (when (buffer-live-p buffer)
     (with-current-buffer buffer
       (setq erc--server-reconnect-timeout
@@ -857,7 +870,8 @@ Expect BUFFER to be the server buffer for the current connection."
                              (with-current-buffer buffer
                                (let ((erc-server-reconnect-timeout
                                       erc--server-reconnect-timeout))
-                                 (delete-process proc)
+                                 (when proc ; conn refused w/o :nowait
+                                   (delete-process proc))
                                  (erc-display-message nil 'error buffer
                                                       "Nobody home...")
                                  (erc-schedule-reconnect buffer 0))))))
@@ -867,7 +881,7 @@ Expect BUFFER to be the server buffer for the current connection."
              (conchk (lambda (proc)
                        (let ((status (process-status proc))
                              (xprdp (time-less-p conchk-exp (current-time))))
-                         (when (or (not (eq 'connect status)) xprdp)
+                         (when (or xprdp (not (eq 'connect status)))
                            (cancel-timer conchk-timer))
                          (when (buffer-live-p buffer)
                            (cond (xprdp (erc-display-message
@@ -880,38 +894,50 @@ Expect BUFFER to be the server buffer for the current connection."
              (sentinel (lambda (proc event)
                          (pcase event
                            ("open\n"
-                            (run-at-time nil nil #'process-send-string proc
-                                         (format "PING %d\r\n"
-                                                 (time-convert nil 'integer))))
+                            (let ((cookie (time-convert nil 'integer)))
+                              (process-put proc 'erc--reconnect-cookie cookie)
+                              (run-at-time nil nil #'process-send-string proc
+                                           (format "PING %d\r\n" cookie))))
                            ((or "connection broken by remote peer\n"
                                 (rx bot "failed"))
                             (run-at-time nil nil reschedule proc)))))
-             (filter (lambda (proc _)
-                       (delete-process proc)
+             (filter (lambda (proc string)
                        (with-current-buffer buffer
                          (setq erc--server-reconnect-timeout nil))
-                       (run-at-time nil nil #'erc-server-delayed-reconnect
-                                    buffer))))
+                       (if-let* ; reuse proc if string has complete message
+                           ((cookie (process-get proc 'erc--reconnect-cookie))
+                            ((string-suffix-p (format "PONG %d\r\n" cookie)
+                                              string))) ; leading ":<source> "
+                           (progn
+                             (erc-log-irc-protocol string nil)
+                             (set-process-sentinel proc #'ignore)
+                             (set-process-filter proc nil)
+                             (run-at-time nil nil
+                                          #'erc-server--reconnect-opened
+                                          buffer proc))
+                         (delete-process proc)
+                         (run-at-time nil nil #'erc-server-delayed-reconnect
+                                      buffer)))))
         (condition-case _
             (let ((proc (funcall erc-session-connector
                                  "*erc-connectivity-check*" nil
-                                 erc-session-server erc-session-port
-                                 :nowait t)))
+                                 erc-session-server erc-session-port)))
               (setq conchk-timer (run-at-time 1 1 conchk proc))
               (set-process-filter proc filter)
-              (set-process-sentinel proc sentinel))
+              (set-process-sentinel proc sentinel)
+              (when (eq (process-status proc) 'open) ; :nowait is nil
+                (funcall sentinel proc "open\n")))
+          ;; E.g., "make client process failed" "Connection refused".
           (file-error (funcall reschedule nil)))))))
 
-(defvar erc--server-delayed-check-connectors
-  '(erc-open-tls-stream erc-open-network-stream)
-  "Functions compatible with `erc-server-delayed-check-reconnect'.")
-
 (defun erc-server-prefer-check-reconnect (buffer)
   "Defer to another reconnector based on BUFFER's `erc-session-connector'.
 Prefer `erc-server-delayed-check-reconnect' if the connector is known to
 be \"check-aware\".  Otherwise, use `erc-server-delayed-reconnect'."
   (if (memq (buffer-local-value 'erc-session-connector buffer)
-            erc--server-delayed-check-connectors)
+            '(erc-open-tls-stream
+              erc-open-network-stream
+              erc-open-socks-tls-stream))
       (erc-server-delayed-check-reconnect buffer)
     (erc-server-delayed-reconnect buffer)))
 
index d6a114147b3a6d07264be6a5918bf01b48ae7c50..adde30e6d473a07a92691d9fe58eea4f8e3f7f33 100644 (file)
       ((erc-server-flood-penalty 0.1)
        (erc-scenarios-common-dialog "base/reconnect")
        (erc-d-auto-pong nil)
+       (erc-d-tmpl-vars
+        `((cookie . ,(lambda (a) (funcall a :set (funcall a :match 1))))))
        (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect))
        (port (process-contact dumb-server :service))
        (erc--server-reconnect-timeout-scale-function (lambda (_) 1))
     (ert-info ("Service restored")
       (setq dumb-server (erc-d-run "localhost" port
                                    'just-ping
-                                   'ping-pong
                                    'unexpected-disconnect))
       (with-current-buffer "FooNet"
         (funcall expect 30 "server is in debug mode")))
diff --git a/test/lisp/erc/resources/base/reconnect/ping-pong.eld b/test/lisp/erc/resources/base/reconnect/ping-pong.eld
deleted file mode 100644 (file)
index b3d36cf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-;; -*- mode: lisp-data; -*-
-((ping 10 "PING ")
- (0 "PONG fake"))
-
-((eof 10 EOF))
-((drop 0 DROP))
index 80903f9415537fe9095202e4560b9d4ffe2200be..281239dfdaa3344aa3ca9457f91842f4a14cc782 100644 (file)
@@ -1,7 +1,8 @@
 ;; -*- mode: lisp-data; -*-
 
 ((~eof 60 EOF))
-((~ping 60 "PING"))
+((~ping 60 "PING " (group (+ (in "0-9"))))
+ (0 "PONG " cookie))
 
 ((nick 10 "NICK tester"))
 ((user 10 "USER user 0 * :tester")
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-solo.eld b/test/lisp/erc/resources/erc-d/resources/proxy-solo.eld
deleted file mode 100644 (file)
index af216c8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-;;; -*- mode: lisp-data -*-
-
-((pass 10.0 "PASS " (? ?:) "changeme"))
-((nick 0.2 "NICK tester"))
-
-((user 0.2 "USER user 0 * :" (group (+ alpha)) eos)
- (0 ":*status!znc@znc.in NOTICE " nick " :You have no networks configured."
-    " Use /znc AddNetwork <network> to add one.")
- (0 ":irc.znc.in 001 " nick " :Welcome " nick "!"))