Reuse process in erc-server-delayed-check-reconnect

* 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)
This commit is contained in:
F. Jason Park 2024-12-23 22:21:34 -08:00
parent a99e1cc745
commit f5ebe47ba7
6 changed files with 62 additions and 35 deletions

View 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

View 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)))

View file

@ -100,6 +100,8 @@
((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))
@ -128,7 +130,6 @@
(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")))

View file

@ -1,6 +0,0 @@
;; -*- mode: lisp-data; -*-
((ping 10 "PING ")
(0 "PONG fake"))
((eof 10 EOF))
((drop 0 DROP))

View 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")

View file

@ -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 "!"))