unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
@ 2023-03-08  6:12 xoddf2
  2023-03-08  7:56 ` J.P.
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: xoddf2 @ 2023-03-08  6:12 UTC (permalink / raw)
  To: 62044; +Cc: emacs-erc


Even with the following settings:

(setq erc-server-auto-reconnect t
      erc-server-reconnect-timeout 10
      erc-server-reconnect-attempts t)

ERC does not reconnect to my ZNC bouncer after a network outage.  The
echo area reads "Connecting to example.net:6697..." and "Logging in as
`user'...", but ERC never actually reconnects, even after connectivity
is restored.  The mode line continues to read "(ERC: CLOSED Fly/--)".


In GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version
 3.24.36, cairo version 1.16.0) of 2023-03-07, unofficial emacs-snapshot
 build: http://emacs.secretsauce.net built on fatty
Windowing system distributor 'The X.Org Foundation', version 11.0.12101007
System Description: Debian GNU/Linux bookworm/sid

Configured using:
 'configure --build x86_64-linux-gnu --prefix=/usr
 --sharedstatedir=/var/lib --libexecdir=/usr/lib
 --localstatedir=/var/lib --infodir=/usr/share/info
 --mandir=/usr/share/man --enable-libsystemd --with-native-compilation
 --with-pop=yes --with-tree-sitter
 --enable-locallisppath=/etc/emacs-snapshot:/etc/emacs:/usr/local/share/emacs/30.0.50/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/30.0.50/site-lisp:/usr/share/emacs/site-lisp
 --build x86_64-linux-gnu --prefix=/usr --sharedstatedir=/var/lib
 --libexecdir=/usr/lib --localstatedir=/var/lib
 --infodir=/usr/share/info --mandir=/usr/share/man --enable-libsystemd
 --with-native-compilation --with-pop=yes --with-tree-sitter
 --enable-locallisppath=/etc/emacs-snapshot:/etc/emacs:/usr/local/share/emacs/30.0.50/site-lisp:/usr/local/share/emacs/site-lisp:/usr/share/emacs/30.0.50/site-lisp:/usr/share/emacs/site-lisp
 --with-x=yes --with-imagemagick --with-x-toolkit=gtk3
 --with-toolkit-scroll-bars 'CFLAGS=-g -O2
 -ffile-prefix-map=/build/emacs-snapshot-Vc6LHg/emacs-snapshot-20230307+emacs-28.2-164473-g4e8b50ec57b=. -fstack-protector-strong
 -Wformat -Werror=format-security -Wall -fno-omit-frame-pointer'
 'CPPFLAGS=-Wdate-time -D_FORTIFY_SOURCE=2' LDFLAGS=-Wl,-z,relro'

Configured features:
ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ
IMAGEMAGICK JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2
M17N_FLT MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PNG RSVG SECCOMP
SOUND THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER WEBP X11 XDBE XIM
XINPUT2 XPM GTK3 ZLIB

Important settings:
  value of $LANG: en_US.UTF-8
  value of $XMODIFIERS: @im=ibus
  locale-coding-system: utf-8-unix

Major mode: ERC

Minor modes in effect:
  erc-spelling-mode: t
  flyspell-mode: t
  erc-log-mode: t
  erc-autoaway-mode: t
  erc-list-mode: t
  erc-menu-mode: t
  erc-autojoin-mode: t
  erc-ring-mode: t
  erc-pcomplete-mode: t
  erc-track-mode: t
  erc-track-minor-mode: t
  erc-netsplit-mode: t
  erc-ercn-mode: t
  erc-match-mode: t
  erc-hl-nicks-mode: t
  erc-button-mode: t
  erc-stamp-mode: t
  erc-irccontrols-mode: t
  erc-noncommands-mode: t
  erc-move-to-prompt-mode: t
  erc-readonly-mode: t
  erc-networks-mode: t
  override-global-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  line-number-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t

Load-path shadows:
/usr/share/emacs/30.0.50/site-lisp/debian-startup hides /usr/share/emacs/site-lisp/debian-startup
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-context hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-context
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-contrib hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-contrib
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-server hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-server
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-icalendar hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-icalendar
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-update hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-update
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-main hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-main
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-config hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-config
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-actions hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-actions
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-pkg hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-pkg
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-lists hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-lists
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-helpers hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-helpers
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-bookmarks hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-bookmarks
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-headers hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-headers
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-message hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-message
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-search hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-search
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-compose hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-compose
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-contacts hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-contacts
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-speedbar hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-speedbar
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-folders hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-folders
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-mark hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-mark
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-view hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-view
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-vars hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-vars
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-org hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-org
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-draft hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-draft
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-autoloads hides /usr/share/emacs/site-lisp/elpa/mu4e-1.8.14/mu4e-autoloads
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-context hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-context
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-server hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-server
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-icalendar hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-icalendar
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-main hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-main
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-config hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-config
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-pkg hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-pkg
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-lists hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-lists
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-helpers hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-helpers
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-message hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-message
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-search hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-search
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-compose hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-compose
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-update hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-update
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-speedbar hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-speedbar
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-folders hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-folders
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-headers hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-headers
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-view hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-view
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-vars hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-vars
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-org hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-org
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-contrib hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-contrib
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-actions hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-actions
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-contacts hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-contacts
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-mark hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-mark
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-draft hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-draft
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-autoloads hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-autoloads
/usr/share/emacs/30.0.50/site-lisp/elpa/mu4e-1.8.14/mu4e-bookmarks hides /usr/share/emacs/site-lisp/elpa-src/mu4e-1.8.14/mu4e-bookmarks
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-bind-key hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-bind-key
/home/xoddf2/.emacs.d/elpa/bind-key-20230203.2004/bind-key hides /usr/share/emacs/30.0.50/lisp/use-package/bind-key
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-ensure hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-ensure
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-delight hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-delight
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-core hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-core
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-diminish hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-diminish
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-jump hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-jump
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package hides /usr/share/emacs/30.0.50/lisp/use-package/use-package
/home/xoddf2/.emacs.d/elpa/use-package-20230203.2004/use-package-lint hides /usr/share/emacs/30.0.50/lisp/use-package/use-package-lint

Features:
(shadow emacsbug cl-print help-fns radix-tree misearch multi-isearch
mule-util display-line-numbers znc advice cl smiley gnus-bcklg
gnus-async qp gnus-ml disp-table mailalias smtpmail textsec uni-scripts
idna-mapping ucs-normalize uni-confusable textsec-check sort gnus-cite
mail-extr nndraft nnmh nnfolder utf-7 network-stream nsm gnus-agent
gnus-srvr gnus-score score-mode nnvirtual gnus-msg gnus-art mm-uu
mml2015 mm-view mml-smime smime gnutls dig nntp gnus-cache gnus-sum shr
pixel-fill kinsoku url-file svg dom gnus-group gnus-undo gnus-start
gnus-dbus dbus xml gnus-cloud nnimap nnmail mail-source utf7 nnoo
gnus-spec gnus-int gnus-range message sendmail yank-media puny dired
dired-loaddefs rfc822 mml mml-sec epa derived epg rfc6068 epg-config
mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045
ietf-drums mailabbrev gmm-utils mailheader gnus-win gnus nnheader
gnus-util text-property-search mail-utils range mm-util mail-prsvr comp
comp-cstr warnings icons rx rcirc parse-time erc-spelling flyspell
ispell erc-log erc-autoaway ercn erc-list erc-menu erc-join erc-ring
erc-pcomplete pcomplete comint ansi-osc ansi-color ring erc-track
erc-netsplit dash erc-match erc-hl-nicks color erc-button erc-fill
erc-stamp wid-edit erc-goodies erc iso8601 time-date thingatpt pp
format-spec erc-backend erc-networks erc-common erc-compat erc-loaddefs
edmacro kmacro cl-extra help-mode use-package-bind-key bind-key
easy-mmode use-package-ensure use-package-core modus-operandi-theme
modus-vivendi-theme modus-themes finder-inf znc-autoloads ercn-autoloads
erc-hl-nicks-autoloads mu4e-alert-autoloads s-autoloads ht-autoloads
info dash-autoloads package browse-url url url-proxy url-privacy
url-expand url-methods url-history url-cookie generate-lisp-file
url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq
eieio eieio-core cl-macs password-cache json subr-x map byte-opt gv
bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc iso-transl tooltip
cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type
elisp-mode mwheel term/x-win x-win term/common-win x-dnd tool-bar dnd
fontset image regexp-opt fringe tabulated-list replace newcomment
text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow
isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax
font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify lcms2
dynamic-setting system-font-setting font-render-setting cairo
move-toolbar gtk x-toolkit xinput2 x multi-tty make-network-process
native-compile emacs)

Memory information:
((conses 16 1404652 266149)
 (symbols 48 29853 4)
 (strings 32 168672 35742)
 (string-bytes 1 3955639)
 (vectors 16 108362)
 (vector-slots 8 2328169 166965)
 (floats 8 496 169)
 (intervals 56 49583 4814)
 (buffers 984 45))

-- 
xoddf2 | https://wlair.us.to/ | PGP: 20EB90D3





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
  2023-03-08  6:12 bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken xoddf2
@ 2023-03-08  7:56 ` J.P.
       [not found] ` <87pm9jy8v7.fsf@neverwas.me>
  2024-04-29  9:56 ` bug#62044: Status update? Alexis
  2 siblings, 0 replies; 12+ messages in thread
From: J.P. @ 2023-03-08  7:56 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

Hi xoddf2,

xoddf2 <woddfellow2@gmail.com> writes:

> Even with the following settings:
>
> (setq erc-server-auto-reconnect t
>       erc-server-reconnect-timeout 10
>       erc-server-reconnect-attempts t)
>
> ERC does not reconnect to my ZNC bouncer after a network outage.  The
> echo area reads "Connecting to example.net:6697..." and "Logging in as
> `user'...", but ERC never actually reconnects, even after connectivity
> is restored.  The mode line continues to read "(ERC: CLOSED Fly/--)".

Thanks for filing this bug. From your comments on Libera, it appears
this problem has been haunting you since at least ERC 5.4 and that it
also occurs with emacs -Q. If either of those is untrue, please correct
the record. For starters, we need to find a recipe, all the way from
emacs -Q, that triggers the unwanted behavior. That way, we can dispense
with any possible complications arising from your init.el and any
third-party packages, e.g.,

> Major mode: ERC
[...]
>   erc-netsplit-mode: t
>   erc-ercn-mode: t
    ^~~~~~~~~~~~~~
>   erc-match-mode: t
>   erc-hl-nicks-mode: t
    ^~~~~~~~~~~~~~~~~
[...]
>
> Features:
> (shadow emacsbug cl-print help-fns radix-tree misearch multi-isearch
> mule-util display-line-numbers znc advice cl smiley gnus-bcklg
                                 ^~~

Also, please be as specific as possible when describing connection
parameters, whether assigned to user options or provided via entry-point
arguments to `erc-tls'. For example, if you give a keyword argument of

  :user "me@laptop/libera"

to `erc-tls', please provide something similar in the recipe, rather
than simply

  :user "$user"

And if you use auth-source, please describe the specific back end and,
if possible, the rough contents of any relevant files.

Typically, if we make it to the "Logging in as" phase, we can rule out
TLS- and process-related issues (for now) and instead focus on logical
connection parameters, such as the various `erc-session-foo' variables.
If you don't mind, please do the following before connecting for the
first time in a new -Q session:

  (require 'erc)
  (erc-toggle-debug-irc-protocol) 
  (setq erc-server-reconnect-timeout 60)
  (trace-function-background 'erc--register-connection)
  (trace-function-background 'erc-auth-source-search)
  (trace-function-background 'erc-login)
  (trace-function-background 'erc-open)
  (trace-function-background 'erc-open-network-stream)
  (trace-function-background 'erc-open-tls-stream)
  (trace-function-background 'erc-process-sentinel)
  (trace-function-background 'erc-process-sentinel-1)
  (trace-function-background 'erc-process-sentinel-2)
  (trace-function-background 'erc-schedule-reconnect)
  (trace-function-background 'erc-server-connect)
  (trace-function-background 'erc-server-reconnect)

And, after witnessing the bug, please provide the output of the
*erc-protocol* and *trace-output* buffers (out of band, if necessary,
though ideally with minimal redactions, aside from credentials) along
with the -Q recipe mentioned earlier.

Thanks again,
J.P.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found] ` <87pm9jy8v7.fsf@neverwas.me>
@ 2023-03-08  9:07   ` xoddf2
       [not found]   ` <87sfefr4qa.fsf@gmail.com>
  1 sibling, 0 replies; 12+ messages in thread
From: xoddf2 @ 2023-03-08  9:07 UTC (permalink / raw)
  To: 62044, emacs-erc


J.P. writes:

> Hi xoddf2,
>
> [...] For starters, we need to find a recipe, all the way from
> emacs -Q, that triggers the unwanted behavior. That way, we can dispense
> with any possible complications arising from your init.el and any
> third-party packages [...]

After running emacs-snapshot -Q, I yanked the below Emacs Lisp code into
the *scratch* buffer, evaluated it, then ran M-x erc.  I left server and
port at default (irc.libera.chat and 6667, respectively), set nick to
aoddf2, and left the server password blank.  I then joined ##test.  I
said something in that channel from my usual client, disconnected the VM
from the network in NetworkManager Applet, and then waited a few
minutes.  I reconnected and then waited again.  ERC had still not
reconnected.

> [...]
>
> Typically, if we make it to the "Logging in as" phase, we can rule out
> TLS- and process-related issues (for now) and instead focus on logical
> connection parameters, such as the various `erc-session-foo' variables.
> If you don't mind, please do the following before connecting for the
> first time in a new -Q session:
>
>   (require 'erc)
>   (erc-toggle-debug-irc-protocol) 
>   (setq erc-server-reconnect-timeout 60)
>   (trace-function-background 'erc--register-connection)
>   (trace-function-background 'erc-auth-source-search)
>   (trace-function-background 'erc-login)
>   (trace-function-background 'erc-open)
>   (trace-function-background 'erc-open-network-stream)
>   (trace-function-background 'erc-open-tls-stream)
>   (trace-function-background 'erc-process-sentinel)
>   (trace-function-background 'erc-process-sentinel-1)
>   (trace-function-background 'erc-process-sentinel-2)
>   (trace-function-background 'erc-schedule-reconnect)
>   (trace-function-background 'erc-server-connect)
>   (trace-function-background 'erc-server-reconnect)
>
> And, after witnessing the bug, please provide the output of the
> *erc-protocol* and *trace-output* buffers (out of band, if necessary,
> though ideally with minimal redactions, aside from credentials) along
> with the -Q recipe mentioned earlier.

*erc-protocol*:

Version: 2
ERC-Version: 5.5
Emacs-Version: 30.0.50
*** This buffer displays all IRC protocol traffic exchanged with servers.
*** Kill it to disable logging.
*** Press t to toggle.*** IRC protocol logging enabled at Wed Mar  8 00:34:44 2023

2023-03-08T00:35:02.020240-0800 irc.libera.chat:6667 >> NICK aoddf2
2023-03-08T00:35:02.020406-0800 irc.libera.chat:6667 >> USER user 0 * :unknown
2023-03-08T00:35:02.161418-0800 irc.libera.chat:6667 << :lead.libera.chat NOTICE * :*** Checking Ident
2023-03-08T00:35:02.469048-0800 irc.libera.chat:6667 << :lead.libera.chat NOTICE * :*** Looking up your hostname...
2023-03-08T00:35:03.186250-0800 irc.libera.chat:6667 << :lead.libera.chat NOTICE * :*** Found your hostname: [REDACTED]
2023-03-08T00:35:08.306391-0800 irc.libera.chat:6667 << :lead.libera.chat NOTICE * :*** No Ident response
2023-03-08T00:35:08.306787-0800 irc.libera.chat:6667 << :lead.libera.chat 001 aoddf2 :Welcome to the Libera.Chat Internet Relay Chat Network aoddf2
2023-03-08T00:35:08.307200-0800 irc.libera.chat:6667 << :lead.libera.chat 002 aoddf2 :Your host is lead.libera.chat[94.125.182.252/6667], running version solanum-1.0-dev
2023-03-08T00:35:08.307887-0800 irc.libera.chat:6667 << :lead.libera.chat 003 aoddf2 :This server was created Thu Nov 24 2022 at 07:37:25 UTC
2023-03-08T00:35:08.308183-0800 irc.libera.chat:6667 << :lead.libera.chat 004 aoddf2 lead.libera.chat solanum-1.0-dev DGIMQRSZaghilopsuwz CFILMPQRSTbcefgijklmnopqrstuvz bkloveqjfI
2023-03-08T00:35:08.308628-0800 lead.libera.chat << :lead.libera.chat 005 aoddf2 FNC WHOX CALLERID=g ETRACE MONITOR=100 KNOCK SAFELIST ELIST=CMNTU CHANTYPES=# EXCEPTS INVEX CHANMODES=eIbq,k,flj,CFLMPQRSTcgimnprstuz :are supported by this server
2023-03-08T00:35:08.309048-0800 lead.libera.chat << :lead.libera.chat 005 aoddf2 CHANLIMIT=#:250 PREFIX=(ov)@+ MAXLIST=bqeI:100 MODES=4 NETWORK=Libera.Chat STATUSMSG=@+ CASEMAPPING=rfc1459 NICKLEN=16 MAXNICKLEN=16 CHANNELLEN=50 TOPICLEN=390 DEAF=D :are supported by this server
2023-03-08T00:35:08.309509-0800 lead.libera.chat << :lead.libera.chat 005 aoddf2 TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: EXTBAN=$,ajrxz :are supported by this server
2023-03-08T00:35:08.309867-0800 lead.libera.chat << :lead.libera.chat 251 aoddf2 :There are 70 users and 50158 invisible on 28 servers
2023-03-08T00:35:08.310079-0800 lead.libera.chat << :lead.libera.chat 252 aoddf2 37 :IRC Operators online
2023-03-08T00:35:08.310295-0800 lead.libera.chat << :lead.libera.chat 253 aoddf2 41 :unknown connection(s)
2023-03-08T00:35:08.310504-0800 lead.libera.chat << :lead.libera.chat 254 aoddf2 22988 :channels formed
2023-03-08T00:35:08.331744-0800 lead.libera.chat << :lead.libera.chat 255 aoddf2 :I have 3127 clients and 1 servers
2023-03-08T00:35:08.332278-0800 lead.libera.chat << :lead.libera.chat 265 aoddf2 3127 3449 :Current local users 3127, max 3449
2023-03-08T00:35:08.342970-0800 lead.libera.chat << :lead.libera.chat 266 aoddf2 50228 51827 :Current global users 50228, max 51827
2023-03-08T00:35:08.343304-0800 lead.libera.chat << :lead.libera.chat 250 aoddf2 :Highest connection count: 3450 (3449 clients) (314542 connections received)
2023-03-08T00:35:08.343675-0800 lead.libera.chat << :lead.libera.chat 375 aoddf2 :- lead.libera.chat Message of the Day - 
2023-03-08T00:35:08.344067-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Welcome to Libera Chat, the IRC network for
2023-03-08T00:35:08.344270-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- free & open-source software and peer directed projects.
2023-03-08T00:35:08.344460-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :-  
2023-03-08T00:35:08.344615-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Use of Libera Chat is governed by our network policies.
2023-03-08T00:35:08.344813-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :-  
2023-03-08T00:35:08.344974-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- To reduce network abuses we perform open proxy checks
2023-03-08T00:35:08.345192-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- on hosts at connection time.
2023-03-08T00:35:08.345370-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :-  
2023-03-08T00:35:08.345528-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Please visit us in #libera for questions and support.
2023-03-08T00:35:08.345728-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :-  
2023-03-08T00:35:08.345894-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Website and documentation:  https://libera.chat
2023-03-08T00:35:08.346100-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Webchat:                    https://web.libera.chat
2023-03-08T00:35:08.346305-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Network policies:           https://libera.chat/policies
2023-03-08T00:35:08.346508-0800 lead.libera.chat << :lead.libera.chat 372 aoddf2 :- Email:                      support@libera.chat
2023-03-08T00:35:08.346694-0800 lead.libera.chat << :lead.libera.chat 376 aoddf2 :End of /MOTD command.
2023-03-08T00:35:08.347303-0800 Libera.Chat >> MODE aoddf2 +i
2023-03-08T00:35:08.347382-0800 Libera.Chat << :aoddf2 MODE aoddf2 :+iw
2023-03-08T00:35:11.908212-0800 Libera.Chat >> JOIN ##test
2023-03-08T00:35:12.348311-0800 Libera.Chat >> PING 1678264512
2023-03-08T00:35:14.914253-0800 Libera.Chat << :aoddf2!~user@[REDACTED] JOIN ##test
2023-03-08T00:35:14.919775-0800 Libera.Chat >> MODE ##test
2023-03-08T00:35:15.268978-0800 Libera.Chat << :lead.libera.chat 353 aoddf2 @ ##test :aoddf2 xoddf2 lonjil2 Guest82707 jstoker
2023-03-08T00:35:15.269737-0800 Libera.Chat << :lead.libera.chat 366 aoddf2 ##test :End of /NAMES list.
2023-03-08T00:35:15.269837-0800 Libera.Chat << :lead.libera.chat PONG lead.libera.chat :1678264512
2023-03-08T00:35:15.678517-0800 Libera.Chat << :lead.libera.chat 324 aoddf2 ##test +Pnst
2023-03-08T00:35:15.679213-0800 Libera.Chat << :lead.libera.chat 329 aoddf2 ##test 1619537078
2023-03-08T00:35:17.932532-0800 Libera.Chat << :xoddf2!~xoddf2@user/xoddf2 PRIVMSG ##test :...
2023-03-08T00:35:42.357025-0800 Libera.Chat >> PING 1678264542
2023-03-08T00:36:12.366140-0800 Libera.Chat >> PING 1678264572
2023-03-08T00:36:42.378078-0800 Libera.Chat >> PING 1678264602
2023-03-08T00:37:12.378084-0800 Libera.Chat >> PING 1678264632

*trace-output*:

======================================================================
1 -> (erc-open "irc.libera.chat" 6667 "aoddf2" "unknown" t nil nil nil nil nil "user" nil)
| 2 -> (erc-auth-source-search :user "aoddf2")
| 2 <- erc-auth-source-search: nil
| 2 -> (erc-server-connect "irc.libera.chat" 6667 #<buffer irc.libera.chat:6667> nil)
| | 3 -> (erc-open-network-stream "erc-irc.libera.chat-6667" nil "irc.libera.chat" 6667)
| | 3 <- erc-open-network-stream: #<process erc-irc.libera.chat-6667>
| 2 <- erc-server-connect: nil
1 <- erc-open: #<buffer irc.libera.chat:6667>
======================================================================
1 -> (erc-process-sentinel #<process erc-irc.libera.chat-6667> "open\n")
| 2 -> (erc--register-connection)
| | 3 -> (erc-login)
| | 3 <- erc-login: nil
| 2 <- erc--register-connection: nil
1 <- erc-process-sentinel: nil
======================================================================
1 -> (erc-auth-source-search :user "##test")
1 <- erc-auth-source-search: nil
======================================================================
1 -> (erc-open "irc.libera.chat" 6667 "aoddf2" "unknown" nil nil (#1="##test") #1# #<process erc-irc.libera.chat-6667> nil "user" nil)
1 <- erc-open: #<buffer ##test>
======================================================================
1 -> (erc-process-sentinel #<process erc-irc.libera.chat-6667> "deleted\n")
| 2 -> (erc-process-sentinel-1 "deleted\n" #<buffer Libera.Chat>)
| | 3 -> (erc-process-sentinel-2 "deleted\n" #<buffer Libera.Chat>)
| | | 4 -> (erc-schedule-reconnect #<buffer Libera.Chat>)
| | | 4 <- erc-schedule-reconnect: [nil 25608 18834 370932 nil erc-server-delayed-reconnect (#<buffer Libera.Chat>) nil 554000 nil]
| | 3 <- erc-process-sentinel-2: nil
| 2 <- erc-process-sentinel-1: nil
1 <- erc-process-sentinel: nil
======================================================================
1 -> (erc-server-reconnect)
| 2 -> (erc-open "irc.libera.chat" 6667 "aoddf2" "unknown" t nil nil nil nil nil "user" nil)
| | 3 -> (erc-server-connect "irc.libera.chat" 6667 #<buffer Libera.Chat> nil)
| | | 4 -> (erc-open-network-stream "erc-irc.libera.chat-6667" nil "irc.libera.chat" 6667)
| | | 4 <- erc-open-network-stream: #<process erc-irc.libera.chat-6667>
| | 3 <- erc-server-connect: nil
| 2 <- erc-open: #<buffer Libera.Chat>
1 <- erc-server-reconnect: nil

(Only redaction was the hostname.)

>
> Thanks again,
> J.P.


-- 
xoddf2 | https://wlair.us.to/ | PGP: 20EB90D3





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]   ` <87sfefr4qa.fsf@gmail.com>
@ 2023-03-08 16:12     ` J.P.
       [not found]     ` <878rg7ql29.fsf@neverwas.me>
  1 sibling, 0 replies; 12+ messages in thread
From: J.P. @ 2023-03-08 16:12 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

[-- Attachment #1: Type: text/plain, Size: 2447 bytes --]

xoddf2 <woddfellow2@gmail.com> writes:

> J.P. writes:
>
>> Hi xoddf2,
>>
>> [...] For starters, we need to find a recipe, all the way from
>> emacs -Q, that triggers the unwanted behavior. That way, we can dispense
>> with any possible complications arising from your init.el and any
>> third-party packages [...]
>
> After running emacs-snapshot -Q, I yanked the below Emacs Lisp code into
> the *scratch* buffer, evaluated it, then ran M-x erc.  I left server and
> port at default (irc.libera.chat and 6667, respectively), set nick to
> aoddf2, and left the server password blank.  I then joined ##test.  I
> said something in that channel from my usual client, disconnected the VM
> from the network in NetworkManager Applet, and then waited a few
> minutes.  I reconnected and then waited again.  ERC had still not
> reconnected.

Thanks for the logs and the lowdown

As with many things IRC, there are two senses of "connectivity" at play
here with regard to automatic reconnections: network and application. In
your initial report, underlying connectivity is present in some form
because ERC reaches the "Logging in as" stage and attempts to send an
application payload, though there's no telling how far it actually gets.

In your followup, network connectivity is absent due to your
"disconnecting the VM", something confirmed by the logs. While I think
this simulation is worth exploring, we probably shouldn't assume it's
failing in a meaningfully similar way to the real-life connection you're
losing to your bouncer, at least not without trying the settings you
laid out initially and also seeking a better understanding of what the
NM applet is actually doing when you flip the switch.

So to keep things sane, we should probably treat auto-reconnecting
across connectivity gaps as a wishlist item and auto-reconnecting atop
healthy connections as an existing, previously unreported bug. As for
the new feature, I've attached a POC patch that you can try if you're
willing (usage is self-explanatory, but feel free to modify or iterate
as needed). As for the other issue, I think we're going to need some
genuine session logs to really get anywhere. That is, we'll likely need
you to enable logging and tracing during a real session with your
bouncer over a hopefully not-too-prolonged period to capture an actual
reconnect sequence failing. But hold off on that for another round
unless you're feeling adventurous.

Thanks again.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-conditional-erc-server-reconnect-function.patch --]
[-- Type: text/x-patch, Size: 2721 bytes --]

From 7c0d22d187400cf2445044f6526814a72b45a86d Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 8 Mar 2023 06:14:36 -0800
Subject: [PATCH] Add conditional erc-server-reconnect-function

* lisp/erc/erc-backend.el (erc--server-reconnect-timer,
erc-server-delayed-check-reconnect): Add possible alternate value for
option `erc-server-reconnect-function' that only attempts to reconnect
after hearing back from the server.  Also add helper variable.
---
 lisp/erc/erc-backend.el | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 567443f5329..d1738e4f92d 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -744,6 +744,47 @@ erc-server-delayed-reconnect
     (with-current-buffer buffer
       (erc-server-reconnect))))
 
+(defvar-local erc--server-reconnect-timeout nil)
+
+(defun erc-server-delayed-check-reconnect (buffer)
+  "Wait for internet connectivity before trying to reconnect.
+BUFFER is the server buffer for the current connection."
+  (with-current-buffer buffer
+    (setq erc--server-reconnect-timeout
+          (min 300 (* (or erc--server-reconnect-timeout
+                          erc-server-reconnect-timeout)
+                      2)))
+    (let ((reschedule
+           (lambda (proc)
+             (let ((erc-server-reconnect-timeout
+                    erc--server-reconnect-timeout))
+               (with-current-buffer buffer
+                 (delete-process proc)
+                 (erc-display-message nil 'error buffer "Nobody home...")
+                 (erc-schedule-reconnect buffer 0))))))
+      (condition-case _
+          (make-network-process
+           :name "*erc-connectivity-check"
+           :host erc-session-server
+           :service erc-session-port
+           :nowait t
+           :filter
+           (lambda (proc _)
+             (delete-process proc)
+             (with-current-buffer buffer
+               (setq erc--server-reconnect-timeout nil))
+             (run-at-time nil nil #'erc-server-delayed-reconnect buffer))
+           :sentinel
+           (lambda (cproc event)
+             (with-current-buffer buffer
+               (pcase event
+                 ("open\n"
+                  (run-at-time nil nil #'send-string
+                               cproc "PING *connect-check*\r\n"))
+                 ("connection broken by remote peer\n"
+                  (funcall reschedule cproc))))))
+        (file-error (funcall reschedule nil))))))
+
 (defun erc-server-filter-function (process string)
   "The process filter for the ERC server."
   (with-current-buffer (process-buffer process)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]     ` <878rg7ql29.fsf@neverwas.me>
@ 2023-03-09  2:22       ` J.P.
       [not found]       ` <87fsaepsso.fsf@neverwas.me>
  1 sibling, 0 replies; 12+ messages in thread
From: J.P. @ 2023-03-09  2:22 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

[-- Attachment #1: Type: text/plain, Size: 1377 bytes --]

"J.P." <jp@neverwas.me> writes:

> In your initial report, underlying connectivity is present in some
> form because ERC reaches the "Logging in as" stage and attempts to
> send an application payload,

Actually, this is nonsense (forgive me). I seem to have forgotten that
ERC prints this message regardless of whether a connection attempt
succeeds.

> So to keep things sane, we should probably treat auto-reconnecting
> across connectivity gaps as a wishlist item and auto-reconnecting atop
> healthy connections as an existing, previously unreported bug. As for
> the new feature, I've attached a POC patch that you can try if you're
> willing (usage is self-explanatory, but feel free to modify or iterate
> as needed).

I've attached a less sloppy version that probably still fails in some
common cases, but at least it reuses the existing session connector.

> As for the other issue, I think we're going to need some genuine
> session logs to really get anywhere. That is, we'll likely need you to
> enable logging and tracing during a real session with your bouncer
> over a hopefully not-too-prolonged period to capture an actual
> reconnect sequence failing. But hold off on that for another round
> unless you're feeling adventurous.

Actually, I'm not sure we'll be needing these logs after all. Let's
maybe think on it a bit more (if that's acceptable). Thanks.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0000-v1-v2.diff --]
[-- Type: text/x-patch, Size: 3886 bytes --]

From 01a2aa830b73028aecf1f7dae7dadba7467a3144 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 8 Mar 2023 18:04:16 -0800
Subject: [PATCH 0/1] *** NOT A PATCH ***

*** BLURB HERE ***

F. Jason Park (1):
  Add conditional erc-server-reconnect-function

 lisp/erc/erc-backend.el | 56 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

Interdiff:
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index d1738e4f92d..d289df98bab 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -749,6 +749,9 @@ erc--server-reconnect-timeout
 (defun erc-server-delayed-check-reconnect (buffer)
   "Wait for internet connectivity before trying to reconnect.
 BUFFER is the server buffer for the current connection."
+  ;; This may appear to hang for a good while at various places
+  ;; because it calls wait_reading_process_output a bunch.  It does at
+  ;; least sometimes print "Waiting for socket from ..." or similar.
   (with-current-buffer buffer
     (setq erc--server-reconnect-timeout
           (min 300 (* (or erc--server-reconnect-timeout
@@ -763,26 +766,38 @@ erc-server-delayed-check-reconnect
                  (erc-display-message nil 'error buffer "Nobody home...")
                  (erc-schedule-reconnect buffer 0))))))
       (condition-case _
-          (make-network-process
-           :name "*erc-connectivity-check"
-           :host erc-session-server
-           :service erc-session-port
-           :nowait t
-           :filter
-           (lambda (proc _)
-             (delete-process proc)
-             (with-current-buffer buffer
-               (setq erc--server-reconnect-timeout nil))
-             (run-at-time nil nil #'erc-server-delayed-reconnect buffer))
-           :sentinel
-           (lambda (cproc event)
-             (with-current-buffer buffer
-               (pcase event
-                 ("open\n"
-                  (run-at-time nil nil #'send-string
-                               cproc "PING *connect-check*\r\n"))
-                 ("connection broken by remote peer\n"
-                  (funcall reschedule cproc))))))
+          (let ((proc (funcall erc-session-connector
+                               "*erc-connectivity-check" nil
+                               erc-session-server erc-session-port
+                               :nowait t))
+                tls-check)
+            (when (and (not (eq erc-session-connector
+                                #'erc-open-network-stream))
+                       (process-contact proc :tls-parameters))
+              (setq tls-check
+                    (run-at-time
+                     1 1 (lambda (proc)
+                           (unless (eq 'connect (process-status proc))
+                             (cancel-timer tls-check))
+                           (when (eq 'failed (process-status proc))
+                             (funcall reschedule proc)))
+                     proc)))
+            (set-process-filter
+             proc (lambda (proc _)
+                    (delete-process proc)
+                    (with-current-buffer buffer
+                      (setq erc--server-reconnect-timeout nil))
+                    (run-at-time nil nil #'erc-server-delayed-reconnect
+                                 buffer)))
+            (set-process-sentinel
+             proc (lambda (cproc event)
+                    (with-current-buffer buffer
+                      (pcase event
+                        ("open\n"
+                         (run-at-time nil nil #'send-string
+                                      cproc "PING *connect-check*\r\n"))
+                        ("connection broken by remote peer\n"
+                         (funcall reschedule cproc)))))))
         (file-error (funcall reschedule nil))))))
 
 (defun erc-server-filter-function (process string)
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Add-conditional-erc-server-reconnect-function.patch --]
[-- Type: text/x-patch, Size: 3738 bytes --]

From 01a2aa830b73028aecf1f7dae7dadba7467a3144 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 8 Mar 2023 06:14:36 -0800
Subject: [PATCH 1/1] Add conditional erc-server-reconnect-function

* lisp/erc/erc-backend.el (erc--server-reconnect-timer,
erc-server-delayed-check-reconnect): Add possible alternate value for
option `erc-server-reconnect-function' that only attempts to reconnect
after hearing back from the server.  Also add helper variable.
---
 lisp/erc/erc-backend.el | 56 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 567443f5329..d289df98bab 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -744,6 +744,62 @@ erc-server-delayed-reconnect
     (with-current-buffer buffer
       (erc-server-reconnect))))
 
+(defvar-local erc--server-reconnect-timeout nil)
+
+(defun erc-server-delayed-check-reconnect (buffer)
+  "Wait for internet connectivity before trying to reconnect.
+BUFFER is the server buffer for the current connection."
+  ;; This may appear to hang for a good while at various places
+  ;; because it calls wait_reading_process_output a bunch.  It does at
+  ;; least sometimes print "Waiting for socket from ..." or similar.
+  (with-current-buffer buffer
+    (setq erc--server-reconnect-timeout
+          (min 300 (* (or erc--server-reconnect-timeout
+                          erc-server-reconnect-timeout)
+                      2)))
+    (let ((reschedule
+           (lambda (proc)
+             (let ((erc-server-reconnect-timeout
+                    erc--server-reconnect-timeout))
+               (with-current-buffer buffer
+                 (delete-process proc)
+                 (erc-display-message nil 'error buffer "Nobody home...")
+                 (erc-schedule-reconnect buffer 0))))))
+      (condition-case _
+          (let ((proc (funcall erc-session-connector
+                               "*erc-connectivity-check" nil
+                               erc-session-server erc-session-port
+                               :nowait t))
+                tls-check)
+            (when (and (not (eq erc-session-connector
+                                #'erc-open-network-stream))
+                       (process-contact proc :tls-parameters))
+              (setq tls-check
+                    (run-at-time
+                     1 1 (lambda (proc)
+                           (unless (eq 'connect (process-status proc))
+                             (cancel-timer tls-check))
+                           (when (eq 'failed (process-status proc))
+                             (funcall reschedule proc)))
+                     proc)))
+            (set-process-filter
+             proc (lambda (proc _)
+                    (delete-process proc)
+                    (with-current-buffer buffer
+                      (setq erc--server-reconnect-timeout nil))
+                    (run-at-time nil nil #'erc-server-delayed-reconnect
+                                 buffer)))
+            (set-process-sentinel
+             proc (lambda (cproc event)
+                    (with-current-buffer buffer
+                      (pcase event
+                        ("open\n"
+                         (run-at-time nil nil #'send-string
+                                      cproc "PING *connect-check*\r\n"))
+                        ("connection broken by remote peer\n"
+                         (funcall reschedule cproc)))))))
+        (file-error (funcall reschedule nil))))))
+
 (defun erc-server-filter-function (process string)
   "The process filter for the ERC server."
   (with-current-buffer (process-buffer process)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]       ` <87fsaepsso.fsf@neverwas.me>
@ 2023-03-09 14:38         ` J.P.
       [not found]         ` <87lek6kn1b.fsf@neverwas.me>
  1 sibling, 0 replies; 12+ messages in thread
From: J.P. @ 2023-03-09 14:38 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

[-- Attachment #1: Type: text/plain, Size: 857 bytes --]

"J.P." <jp@neverwas.me> writes:

> I've attached a less sloppy version that probably still fails in some
> common cases, but at least it reuses the existing session connector.

I've improved upon this further (v3 attached) by adding a housekeeping
task to monitor the initial server process from creation. Such a move
may be regrettable because it adds yet more complexity to the already
dizzying auto-reconnect landscape. However, I couldn't find a suitable
way to cover common process errors that aren't presented to the sentinel
but still need to engage the reconnect logic.

If this leads to a futile game of whack-a-mole, we'll obviously need to
try a different approach. But if we do more-or-less build on what I've
got so far, we'll definitely need to ensure it agrees with 27 and 28
before spending serious energy on refinement and tests.

Thanks.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0000-v2-v3.diff --]
[-- Type: text/x-patch, Size: 6268 bytes --]

From 7dcccaef52ad4442eabaabe04cd95ffceec048f7 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Thu, 9 Mar 2023 06:33:38 -0800
Subject: [PATCH 0/1] *** NOT A PATCH ***

*** BLURB HERE ***

F. Jason Park (1):
  Add conditional erc-server-reconnect-function

 lisp/erc/erc-backend.el | 93 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 2 deletions(-)

Interdiff:
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index d289df98bab..1030672506e 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -658,6 +658,31 @@ erc--register-connection
   (run-hooks 'erc--server-post-connect-hook)
   (erc-login))
 
+(defvar erc--server-connect-function #'erc--server-propagate-failed-connection
+  "Function called one second after creating a server process.
+Called with the newly created process just before the opening IRC
+protocol exchange.")
+
+(defun erc--server-propagate-failed-connection (process)
+  "Ensure the PROCESS sentinel runs at least once on early failure.
+Act as a watchdog timer to force `erc-process-sentinel' and its
+finalizers, like `erc-disconnected-hook', to run when PROCESS has
+a status of `failed' after one second.  Print the
+`process-exit-status', which can be a number, like 111, or a
+message, like \"TLS negotiation failed\"."
+  (when (eq (process-status process) 'failed)
+    (erc-display-message
+     nil 'error (process-buffer process)
+     (format "Process exit status: %S" (process-exit-status process)))
+    (pcase (process-exit-status process)
+      ((guard erc--server-reconnect-timer))
+      (111
+       (delete-process process))
+      (`(file-error ,(rx "failed") ,(rx "unreachable") . ,_)
+       (erc-process-sentinel process "failed with code -523\n"))
+      ((rx "tls" (+ nonl) "failed")
+       (erc-process-sentinel process "failed with code -525\n")))))
+
 (defvar erc--server-connect-dumb-ipv6-regexp
   ;; Not for validation (gives false positives).
   (rx bot "[" (group (+ (any xdigit digit ":.")) (? "%" (+ alnum))) "]" eot))
@@ -708,9 +733,11 @@ erc-server-connect
                    (with-current-buffer buffer (erc-current-nick))))
     ;; wait with script loading until we receive a confirmation (first
     ;; MOTD line)
-    (if (eq (process-status process) 'connect)
+    (if (process-contact process :nowait)
         ;; waiting for a non-blocking connect - keep the user informed
-        (erc-display-message nil nil buffer "Opening connection..\n")
+        (progn
+          (erc-display-message nil nil buffer "Opening connection..\n")
+          (run-at-time 1 nil erc--server-connect-function process))
       (message "%s...done" msg)
       (erc--register-connection))))
 
@@ -759,9 +786,9 @@ erc-server-delayed-check-reconnect
                       2)))
     (let ((reschedule
            (lambda (proc)
-             (let ((erc-server-reconnect-timeout
-                    erc--server-reconnect-timeout))
-               (with-current-buffer buffer
+             (with-current-buffer buffer
+               (let ((erc-server-reconnect-timeout
+                      erc--server-reconnect-timeout))
                  (delete-process proc)
                  (erc-display-message nil 'error buffer "Nobody home...")
                  (erc-schedule-reconnect buffer 0))))))
@@ -770,18 +797,22 @@ erc-server-delayed-check-reconnect
                                "*erc-connectivity-check" nil
                                erc-session-server erc-session-port
                                :nowait t))
-                tls-check)
-            (when (and (not (eq erc-session-connector
-                                #'erc-open-network-stream))
-                       (process-contact proc :tls-parameters))
-              (setq tls-check
-                    (run-at-time
-                     1 1 (lambda (proc)
-                           (unless (eq 'connect (process-status proc))
-                             (cancel-timer tls-check))
-                           (when (eq 'failed (process-status proc))
-                             (funcall reschedule proc)))
-                     proc)))
+                (check-expire (time-add 10 (current-time)))
+                check-aside)
+            (setq check-aside
+                  (run-at-time
+                   1 1 (lambda (proc)
+                         (when (or (not (eq 'connect (process-status proc)))
+                                   (time-less-p check-expire (current-time)))
+                           (cancel-timer check-aside))
+                         (when (time-less-p check-expire (current-time))
+                           (erc-display-message
+                            nil 'error buffer "Timed out waiting on `connect'")
+                           (delete-process proc)
+                           (funcall reschedule proc))
+                         (when (eq 'failed (process-status proc))
+                           (funcall reschedule proc)))
+                   proc))
             (set-process-filter
              proc (lambda (proc _)
                     (delete-process proc)
@@ -790,14 +821,16 @@ erc-server-delayed-check-reconnect
                     (run-at-time nil nil #'erc-server-delayed-reconnect
                                  buffer)))
             (set-process-sentinel
-             proc (lambda (cproc event)
+             proc (lambda (proc event)
                     (with-current-buffer buffer
                       (pcase event
                         ("open\n"
-                         (run-at-time nil nil #'send-string
-                                      cproc "PING *connect-check*\r\n"))
-                        ("connection broken by remote peer\n"
-                         (funcall reschedule cproc)))))))
+                         (run-at-time
+                          nil nil #'send-string proc
+                          (format "PING %d\r\n" (time-convert nil 'integer))))
+                        ((or "connection broken by remote peer\n"
+                             (rx bot "failed"))
+                         (funcall reschedule proc)))))))
         (file-error (funcall reschedule nil))))))
 
 (defun erc-server-filter-function (process string)
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Add-conditional-erc-server-reconnect-function.patch --]
[-- Type: text/x-patch, Size: 6530 bytes --]

From 7dcccaef52ad4442eabaabe04cd95ffceec048f7 Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 8 Mar 2023 06:14:36 -0800
Subject: [PATCH 1/1] Add conditional erc-server-reconnect-function

* lisp/erc/erc-backend.el (erc--server-reconnect-timer,
erc-server-delayed-check-reconnect): Add possible alternate value for
option `erc-server-reconnect-function' that only attempts to reconnect
after hearing back from the server.  Also add helper variable.
(erc-server-connect): Run erc--server-connect-function for async
processes.
(erc--server-connect-function,
erc--server-propagate-failed-connection): Add connect-function
variable and default value to run on process creation and execute
process-failure handlers.
---
 lisp/erc/erc-backend.el | 93 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 91 insertions(+), 2 deletions(-)

diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 567443f5329..1030672506e 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -658,6 +658,31 @@ erc--register-connection
   (run-hooks 'erc--server-post-connect-hook)
   (erc-login))
 
+(defvar erc--server-connect-function #'erc--server-propagate-failed-connection
+  "Function called one second after creating a server process.
+Called with the newly created process just before the opening IRC
+protocol exchange.")
+
+(defun erc--server-propagate-failed-connection (process)
+  "Ensure the PROCESS sentinel runs at least once on early failure.
+Act as a watchdog timer to force `erc-process-sentinel' and its
+finalizers, like `erc-disconnected-hook', to run when PROCESS has
+a status of `failed' after one second.  Print the
+`process-exit-status', which can be a number, like 111, or a
+message, like \"TLS negotiation failed\"."
+  (when (eq (process-status process) 'failed)
+    (erc-display-message
+     nil 'error (process-buffer process)
+     (format "Process exit status: %S" (process-exit-status process)))
+    (pcase (process-exit-status process)
+      ((guard erc--server-reconnect-timer))
+      (111
+       (delete-process process))
+      (`(file-error ,(rx "failed") ,(rx "unreachable") . ,_)
+       (erc-process-sentinel process "failed with code -523\n"))
+      ((rx "tls" (+ nonl) "failed")
+       (erc-process-sentinel process "failed with code -525\n")))))
+
 (defvar erc--server-connect-dumb-ipv6-regexp
   ;; Not for validation (gives false positives).
   (rx bot "[" (group (+ (any xdigit digit ":.")) (? "%" (+ alnum))) "]" eot))
@@ -708,9 +733,11 @@ erc-server-connect
                    (with-current-buffer buffer (erc-current-nick))))
     ;; wait with script loading until we receive a confirmation (first
     ;; MOTD line)
-    (if (eq (process-status process) 'connect)
+    (if (process-contact process :nowait)
         ;; waiting for a non-blocking connect - keep the user informed
-        (erc-display-message nil nil buffer "Opening connection..\n")
+        (progn
+          (erc-display-message nil nil buffer "Opening connection..\n")
+          (run-at-time 1 nil erc--server-connect-function process))
       (message "%s...done" msg)
       (erc--register-connection))))
 
@@ -744,6 +771,68 @@ erc-server-delayed-reconnect
     (with-current-buffer buffer
       (erc-server-reconnect))))
 
+(defvar-local erc--server-reconnect-timeout nil)
+
+(defun erc-server-delayed-check-reconnect (buffer)
+  "Wait for internet connectivity before trying to reconnect.
+BUFFER is the server buffer for the current connection."
+  ;; This may appear to hang for a good while at various places
+  ;; because it calls wait_reading_process_output a bunch.  It does at
+  ;; least sometimes print "Waiting for socket from ..." or similar.
+  (with-current-buffer buffer
+    (setq erc--server-reconnect-timeout
+          (min 300 (* (or erc--server-reconnect-timeout
+                          erc-server-reconnect-timeout)
+                      2)))
+    (let ((reschedule
+           (lambda (proc)
+             (with-current-buffer buffer
+               (let ((erc-server-reconnect-timeout
+                      erc--server-reconnect-timeout))
+                 (delete-process proc)
+                 (erc-display-message nil 'error buffer "Nobody home...")
+                 (erc-schedule-reconnect buffer 0))))))
+      (condition-case _
+          (let ((proc (funcall erc-session-connector
+                               "*erc-connectivity-check" nil
+                               erc-session-server erc-session-port
+                               :nowait t))
+                (check-expire (time-add 10 (current-time)))
+                check-aside)
+            (setq check-aside
+                  (run-at-time
+                   1 1 (lambda (proc)
+                         (when (or (not (eq 'connect (process-status proc)))
+                                   (time-less-p check-expire (current-time)))
+                           (cancel-timer check-aside))
+                         (when (time-less-p check-expire (current-time))
+                           (erc-display-message
+                            nil 'error buffer "Timed out waiting on `connect'")
+                           (delete-process proc)
+                           (funcall reschedule proc))
+                         (when (eq 'failed (process-status proc))
+                           (funcall reschedule proc)))
+                   proc))
+            (set-process-filter
+             proc (lambda (proc _)
+                    (delete-process proc)
+                    (with-current-buffer buffer
+                      (setq erc--server-reconnect-timeout nil))
+                    (run-at-time nil nil #'erc-server-delayed-reconnect
+                                 buffer)))
+            (set-process-sentinel
+             proc (lambda (proc event)
+                    (with-current-buffer buffer
+                      (pcase event
+                        ("open\n"
+                         (run-at-time
+                          nil nil #'send-string proc
+                          (format "PING %d\r\n" (time-convert nil 'integer))))
+                        ((or "connection broken by remote peer\n"
+                             (rx bot "failed"))
+                         (funcall reschedule proc)))))))
+        (file-error (funcall reschedule nil))))))
+
 (defun erc-server-filter-function (process string)
   "The process filter for the ERC server."
   (with-current-buffer (process-buffer process)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]         ` <87lek6kn1b.fsf@neverwas.me>
@ 2023-03-10  7:34           ` xoddf2
       [not found]           ` <87zg8lawlk.fsf@gmail.com>
  1 sibling, 0 replies; 12+ messages in thread
From: xoddf2 @ 2023-03-10  7:34 UTC (permalink / raw)
  To: J.P.; +Cc: emacs-erc, 62044


J.P. writes:

> [...]
>
> I've improved upon this further (v3 attached) by adding a housekeeping
> task to monitor the initial server process from creation. Such a move
> may be regrettable because it adds yet more complexity to the already
> dizzying auto-reconnect landscape. However, I couldn't find a suitable
> way to cover common process errors that aren't presented to the sentinel
> but still need to engage the reconnect logic.
>
> If this leads to a futile game of whack-a-mole, we'll obviously need to
> try a different approach. But if we do more-or-less build on what I've
> got so far, we'll definitely need to ensure it agrees with 27 and 28
> before spending serious energy on refinement and tests.
>
> Thanks.

Version 3 of the patch works, both with an otherwise unconfigured ERC
and with a full configuration connecting to my bouncer.

I used this setting in both cases:
(setq erc-server-reconnect-function 'erc-server-delayed-check-reconnect)

The first 2 versions did not work at all.

Thanks
-- 
xoddf2 | https://wlair.us.to/ | PGP: 20EB90D3





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]           ` <87zg8lawlk.fsf@gmail.com>
@ 2023-03-11 18:52             ` J.P.
       [not found]             ` <87v8j715om.fsf@neverwas.me>
  1 sibling, 0 replies; 12+ messages in thread
From: J.P. @ 2023-03-11 18:52 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

[-- Attachment #1: Type: text/plain, Size: 1853 bytes --]

xoddf2 <woddfellow2@gmail.com> writes:

> J.P. writes:
>
>> [...]
>>
>> I've improved upon this further (v3 attached) by adding a housekeeping
>> task to monitor the initial server process from creation. Such a move
>> may be regrettable because it adds yet more complexity to the already
>> dizzying auto-reconnect landscape. However, I couldn't find a suitable
>> way to cover common process errors that aren't presented to the sentinel
>> but still need to engage the reconnect logic.
>>
>> If this leads to a futile game of whack-a-mole, we'll obviously need to
>> try a different approach. But if we do more-or-less build on what I've
>> got so far, we'll definitely need to ensure it agrees with 27 and 28
>> before spending serious energy on refinement and tests.
>>
>> Thanks.
>
> Version 3 of the patch works, both with an otherwise unconfigured ERC
> and with a full configuration connecting to my bouncer.
>
> I used this setting in both cases:
> (setq erc-server-reconnect-function 'erc-server-delayed-check-reconnect)

Really appreciate your trying this out.

> The first 2 versions did not work at all.

Right, and the last one still fails under various (hopefully less
common) conditions, such as an outbound firewall dropping rather than
rejecting packets. But the main problem (IMO) is unneeded complexity,
and that stems from a fundamental design flaw in ERC: initializing new
buffers and mode/module resources before creating connections, hence
resorting to a probe to check for connectivity, which is roundabout and
error prone. But until people become willing to accept the many breaking
changes that a redesign would spell, I'm afraid we're stuck relying on
these unfriendly contortions.

As for next steps, I've polished up this patch some and have marked it
for preliminary inclusion in what will become ERC 5.6.

Thanks again.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0000-v3-v4.diff --]
[-- Type: text/x-patch, Size: 22039 bytes --]

From a1d77151295d4c177ea75c723684873cc94875ed Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Sat, 11 Mar 2023 06:46:19 -0800
Subject: [PATCH 0/1] *** NOT A PATCH ***

*** BLURB HERE ***

F. Jason Park (1):
  [5.6] Add probing erc-server-reconnect-function variant

 lisp/erc/erc-backend.el                       | 116 ++++++++++++++-
 .../lisp/erc/erc-scenarios-base-auto-recon.el | 140 ++++++++++++++++++
 .../erc/resources/base/reconnect/just-eof.eld |   3 +
 .../resources/base/reconnect/just-ping.eld    |   4 +
 .../resources/base/reconnect/ping-pong.eld    |   6 +
 .../base/reconnect/unexpected-disconnect.eld  |  24 +++
 .../erc/resources/erc-scenarios-common.el     |   1 +
 7 files changed, 289 insertions(+), 5 deletions(-)
 create mode 100644 test/lisp/erc/erc-scenarios-base-auto-recon.el
 create mode 100644 test/lisp/erc/resources/base/reconnect/just-eof.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/just-ping.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/ping-pong.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld

Interdiff:
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 1030672506e..c6f263fdfba 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -415,8 +415,10 @@ erc-server-reconnect-attempts
 
 (defcustom erc-server-reconnect-timeout 1
   "Number of seconds to wait between successive reconnect attempts.
-
-If a key is pressed while ERC is waiting, it will stop waiting."
+If this value is too low, servers may reject your initial nick
+request upon reconnecting because they haven't yet noticed that
+your previous connection is dead.  If this happens, try setting
+this value to 120 or greater."
   :type 'number)
 
 (defcustom erc-server-reconnect-function 'erc-server-delayed-reconnect
@@ -427,6 +429,7 @@ erc-server-reconnect-function
 and optionally alter the attempts tally."
   :package-version '(ERC . "5.5")
   :type '(choice (function-item erc-server-delayed-reconnect)
+                 (function-item erc-server-delayed-check-reconnect)
                  function))
 
 (defcustom erc-split-line-length 440
@@ -667,18 +670,17 @@ erc--server-propagate-failed-connection
   "Ensure the PROCESS sentinel runs at least once on early failure.
 Act as a watchdog timer to force `erc-process-sentinel' and its
 finalizers, like `erc-disconnected-hook', to run when PROCESS has
-a status of `failed' after one second.  Print the
-`process-exit-status', which can be a number, like 111, or a
-message, like \"TLS negotiation failed\"."
+a status of `failed' after one second.  But only do so when its
+error data is something ERC recognizes.  Print an explanation to
+the server buffer in any case."
   (when (eq (process-status process) 'failed)
     (erc-display-message
      nil 'error (process-buffer process)
      (format "Process exit status: %S" (process-exit-status process)))
     (pcase (process-exit-status process)
-      ((guard erc--server-reconnect-timer))
       (111
-       (delete-process process))
-      (`(file-error ,(rx "failed") ,(rx "unreachable") . ,_)
+       (erc-process-sentinel process "failed with code 111\n"))
+      (`(file-error . ,_)
        (erc-process-sentinel process "failed with code -523\n"))
       ((rx "tls" (+ nonl) "failed")
        (erc-process-sentinel process "failed with code -525\n")))))
@@ -733,7 +735,7 @@ erc-server-connect
                    (with-current-buffer buffer (erc-current-nick))))
     ;; wait with script loading until we receive a confirmation (first
     ;; MOTD line)
-    (if (process-contact process :nowait)
+    (if (eq (process-status process) 'connect)
         ;; waiting for a non-blocking connect - keep the user informed
         (progn
           (erc-display-message nil nil buffer "Opening connection..\n")
@@ -772,66 +774,76 @@ erc-server-delayed-reconnect
       (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
+    #'erc--server-reconnect-timeout-double)
+
+(defun erc--server-reconnect-timeout-double (existing)
+  "Double EXISTING timeout, but cap it at 5 minutes."
+  (min 300 (* (or existing erc-server-reconnect-timeout) 2)))
+
+;; This may appear to hang at various places.  It's assumed that when
+;; *Messages* contains "Waiting for socket ..."  or similar, progress
+;; will be made eventually.
 
 (defun erc-server-delayed-check-reconnect (buffer)
   "Wait for internet connectivity before trying to reconnect.
 BUFFER is the server buffer for the current connection."
-  ;; This may appear to hang for a good while at various places
-  ;; because it calls wait_reading_process_output a bunch.  It does at
-  ;; least sometimes print "Waiting for socket from ..." or similar.
-  (with-current-buffer buffer
-    (setq erc--server-reconnect-timeout
-          (min 300 (* (or erc--server-reconnect-timeout
-                          erc-server-reconnect-timeout)
-                      2)))
-    (let ((reschedule
-           (lambda (proc)
-             (with-current-buffer buffer
-               (let ((erc-server-reconnect-timeout
-                      erc--server-reconnect-timeout))
-                 (delete-process proc)
-                 (erc-display-message nil 'error buffer "Nobody home...")
-                 (erc-schedule-reconnect buffer 0))))))
-      (condition-case _
-          (let ((proc (funcall erc-session-connector
-                               "*erc-connectivity-check" nil
-                               erc-session-server erc-session-port
-                               :nowait t))
-                (check-expire (time-add 10 (current-time)))
-                check-aside)
-            (setq check-aside
-                  (run-at-time
-                   1 1 (lambda (proc)
-                         (when (or (not (eq 'connect (process-status proc)))
-                                   (time-less-p check-expire (current-time)))
-                           (cancel-timer check-aside))
-                         (when (time-less-p check-expire (current-time))
-                           (erc-display-message
-                            nil 'error buffer "Timed out waiting on `connect'")
-                           (delete-process proc)
-                           (funcall reschedule proc))
-                         (when (eq 'failed (process-status proc))
-                           (funcall reschedule proc)))
-                   proc))
-            (set-process-filter
-             proc (lambda (proc _)
-                    (delete-process proc)
-                    (with-current-buffer buffer
-                      (setq erc--server-reconnect-timeout nil))
-                    (run-at-time nil nil #'erc-server-delayed-reconnect
-                                 buffer)))
-            (set-process-sentinel
-             proc (lambda (proc event)
-                    (with-current-buffer buffer
-                      (pcase event
-                        ("open\n"
-                         (run-at-time
-                          nil nil #'send-string proc
-                          (format "PING %d\r\n" (time-convert nil 'integer))))
-                        ((or "connection broken by remote peer\n"
-                             (rx bot "failed"))
-                         (funcall reschedule proc)))))))
-        (file-error (funcall reschedule nil))))))
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (setq erc--server-reconnect-timeout
+            (funcall erc--server-reconnect-timeout-scale-function
+                     erc--server-reconnect-timeout))
+      (let* ((reschedule (lambda (proc)
+                           (when (buffer-live-p buffer)
+                             (with-current-buffer buffer
+                               (let ((erc-server-reconnect-timeout
+                                      erc--server-reconnect-timeout))
+                                 (delete-process proc)
+                                 (erc-display-message nil 'error buffer
+                                                      "Nobody home...")
+                                 (erc-schedule-reconnect buffer 0))))))
+             (conchk-exp (time-add erc--server-reconnect-timeout-check
+                                   (current-time)))
+             (conchk-timer nil)
+             (conchk (lambda (proc)
+                       (let ((status (process-status proc))
+                             (top (time-less-p conchk-exp (current-time))))
+                         (when (or (not (eq 'connect status)) top)
+                           (cancel-timer conchk-timer))
+                         (when (buffer-live-p buffer)
+                           (cond (top (erc-display-message
+                                       nil 'error buffer
+                                       "Timed out while dialing...")
+                                      (delete-process proc)
+                                      (funcall reschedule proc))
+                                 ((eq 'failed status)
+                                  (funcall reschedule proc)))))))
+             (sentinel (lambda (proc event)
+                         (pcase event
+                           ("open\n"
+                            (run-at-time
+                             nil nil #'send-string proc
+                             (format "PING %d\r\n"
+                                     (time-convert nil 'integer))))
+                           ((or "connection broken by remote peer\n"
+                                (rx bot "failed"))
+                            (funcall reschedule proc)))))
+             (filter (lambda (proc _)
+                       (delete-process proc)
+                       (with-current-buffer buffer
+                         (setq erc--server-reconnect-timeout nil))
+                       (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)))
+              (setq conchk-timer (run-at-time 1 1 conchk proc))
+              (set-process-filter proc filter)
+              (set-process-sentinel proc sentinel))
+          (file-error (funcall reschedule nil)))))))
 
 (defun erc-server-filter-function (process string)
   "The process filter for the ERC server."
@@ -912,11 +924,16 @@ erc-schedule-reconnect
 `erc-server-reconnect-count' by INCR unconditionally."
   (let ((count (and (integerp erc-server-reconnect-attempts)
                     (- erc-server-reconnect-attempts
-                       (cl-incf erc-server-reconnect-count (or incr 1))))))
-    (erc-display-message nil 'error (current-buffer) 'reconnecting
+                       (cl-incf erc-server-reconnect-count (or incr 1)))))
+        (proc (buffer-local-value 'erc-server-process buffer)))
+    (erc-display-message nil 'error buffer 'reconnecting
                          ?m erc-server-reconnect-timeout
                          ?i (if count erc-server-reconnect-count "N")
                          ?n (if count erc-server-reconnect-attempts "A"))
+    (set-process-sentinel proc #'ignore)
+    (set-process-filter proc nil)
+    (delete-process proc)
+    (erc-update-mode-line)
     (setq erc-server-reconnecting nil
           erc--server-reconnect-timer
           (run-at-time erc-server-reconnect-timeout nil
diff --git a/test/lisp/erc/erc-scenarios-base-auto-recon.el b/test/lisp/erc/erc-scenarios-base-auto-recon.el
new file mode 100644
index 00000000000..719cf4e3b5d
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-auto-recon.el
@@ -0,0 +1,140 @@
+;;; erc-scenarios-base-auto-recon.el --- auto-recon scenarios -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(defun erc-scenarios-base-auto-recon--get-unused-port ()
+  (let ((server (make-network-process :name "*erc-scenarios-base-auto-recon*"
+                                      :host "localhost"
+                                      :service t
+                                      :server t)))
+    (delete-process server)
+    (process-contact server :service)))
+
+;; This demos one possible flavor of intermittent service.
+;; It may end up needing to be marked :unstable.
+(ert-deftest erc-scenarios-base-auto-recon-unavailable ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-server-flood-penalty 0.1)
+       (port (erc-scenarios-base-auto-recon--get-unused-port))
+       (erc--server-reconnect-timeout-scale-function (lambda (_) 1))
+       (erc-server-auto-reconnect t)
+       (erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
+       (expect (erc-d-t-make-expecter))
+       (erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server nil))
+
+    (ert-info ("Dialing fails: nobody home")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+        (erc-d-t-wait-for 10 erc--server-reconnect-timer)
+        (funcall expect 10 "Opening connection")
+        (funcall expect 10 "failed")
+
+        (ert-info ("Reconnect function freezes attempts at 1")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home"))))
+
+    (ert-info ("Service appears")
+      (setq dumb-server (erc-d-run "localhost" port
+                                   'just-eof 'unexpected-disconnect))
+      (with-current-buffer (format "127.0.0.1:%d" port)
+        (funcall expect 10 "server is in debug mode")
+        (should (equal (buffer-name) "FooNet"))))
+
+    (ert-info ("Service interrupted, reconnect starts again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))))
+
+    (ert-info ("Service restored")
+      (delete-process dumb-server)
+      (setq dumb-server (erc-d-run "localhost" port
+                                   'just-eof 'unexpected-disconnect))
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "server is in debug mode")))
+
+    (ert-info ("Service interrupted a third time, reconnect starts yet again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+        (erc-cmd-RECONNECT "cancel")
+        (funcall expect 10 "canceled")))))
+
+;; In this test, a listener accepts but doesn't respond to any messages.
+
+(ert-deftest erc-scenarios-base-auto-recon-no-proto ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-server-flood-penalty 0.1)
+       (erc-scenarios-common-dialog "base/reconnect")
+       (erc-d-auto-pong nil)
+       (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect))
+       (port (process-contact dumb-server :service))
+       (erc--server-reconnect-timeout-scale-function (lambda (_) 1))
+       (erc--server-reconnect-timeout-check 0.5)
+       (erc-server-auto-reconnect t)
+       (erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Session succeeds but cut short")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (funcall expect 10 "server is in debug mode")
+        (should (equal (buffer-name) "FooNet"))
+        (erc-d-t-wait-for 10 erc--server-reconnect-timer)
+        (delete-process dumb-server)
+        (funcall expect 10 "failed")
+
+        (ert-info ("Reconnect function freezes attempts at 1")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home")
+          (funcall expect 10 "timed out while dialing")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home"))))
+
+    (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")))
+
+    (ert-info ("Service interrupted again, reconnect starts again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+        (erc-cmd-RECONNECT "cancel")
+        (funcall expect 10 "canceled")))))
+
+;;; erc-scenarios-base-auto-recon.el ends here
diff --git a/test/lisp/erc/resources/base/reconnect/just-eof.eld b/test/lisp/erc/resources/base/reconnect/just-eof.eld
new file mode 100644
index 00000000000..c80a39b3170
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/just-eof.eld
@@ -0,0 +1,3 @@
+;; -*- mode: lisp-data; -*-
+((eof 5 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/just-ping.eld b/test/lisp/erc/resources/base/reconnect/just-ping.eld
new file mode 100644
index 00000000000..d57888b42d3
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/just-ping.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((ping 20 "PING"))
+
+((eof 10 EOF))
diff --git a/test/lisp/erc/resources/base/reconnect/ping-pong.eld b/test/lisp/erc/resources/base/reconnect/ping-pong.eld
new file mode 100644
index 00000000000..b3d36cf6cec
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/ping-pong.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((ping 10 "PING ")
+ (0 "PONG fake"))
+
+((eof 10 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld b/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld
new file mode 100644
index 00000000000..386d0f4b085
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el
index 0d9a79ae9ce..f259c88594b 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -121,6 +121,7 @@ erc-scenarios-common--print-trace
       (erc-modules (copy-sequence erc-modules))
       (inhibit-interaction t)
       (auth-source-do-cache nil)
+      (timer-list (copy-sequence timer-list))
       (erc-auth-source-parameters-join-function nil)
       (erc-autojoin-channels-alist nil)
       (erc-server-auto-reconnect nil)
-- 
2.39.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-5.6-Add-probing-erc-server-reconnect-function-varian.patch --]
[-- Type: text/x-patch, Size: 20914 bytes --]

From a1d77151295d4c177ea75c723684873cc94875ed Mon Sep 17 00:00:00 2001
From: "F. Jason Park" <jp@neverwas.me>
Date: Wed, 8 Mar 2023 06:14:36 -0800
Subject: [PATCH 1/1] [5.6] Add probing erc-server-reconnect-function variant

* lisp/erc/erc-backend.el (erc-server-reconnect-timeout): Replace
questionable claim with recommendation for alternate value when
experiencing nick rejections.
(erc-server-reconnect-function): Add new value
`erc-server-delayed-check-reconnect'.
(erc--server-reconnect-timer,
erc-server-delayed-check-reconnect): Add possible alternate value for
option `erc-server-reconnect-function' that only attempts to reconnect
after hearing back from the server.  Also add helper variable.
(erc-server-connect): Run erc--server-connect-function for async
processes.
(erc--server-connect-function,
erc--server-propagate-failed-connection): Add connect-function
variable and default value to run on process creation and execute
process-failure handlers.
(erc--server-reconnect-timeout-scale-function,
erc--server-reconnect-timeout-double,
erc--server-reconnect-timeout-check): Add supporting variables and
functions for `erc-server-delayed-check-reconnect'.
(erc-schedule-reconnect): Ensure previous `erc-server-process' is
deleted.
* test/lisp/erc/erc-scenarios-base-auto-recon.el: New file.
* test/lisp/erc/resources/base/reconnect/just-eof.eld: New file.
* test/lisp/erc/resources/base/reconnect/just-ping.eld: New file.
* test/lisp/erc/resources/base/reconnect/ping-pong.eld: New file.
* test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld:
New file.
* test/lisp/erc/resources/erc-scenarios-common.el
(erc-scenarios-common--make-bindings): Shadow timer-list.
---
 lisp/erc/erc-backend.el                       | 116 ++++++++++++++-
 .../lisp/erc/erc-scenarios-base-auto-recon.el | 140 ++++++++++++++++++
 .../erc/resources/base/reconnect/just-eof.eld |   3 +
 .../resources/base/reconnect/just-ping.eld    |   4 +
 .../resources/base/reconnect/ping-pong.eld    |   6 +
 .../base/reconnect/unexpected-disconnect.eld  |  24 +++
 .../erc/resources/erc-scenarios-common.el     |   1 +
 7 files changed, 289 insertions(+), 5 deletions(-)
 create mode 100644 test/lisp/erc/erc-scenarios-base-auto-recon.el
 create mode 100644 test/lisp/erc/resources/base/reconnect/just-eof.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/just-ping.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/ping-pong.eld
 create mode 100644 test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld

diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 567443f5329..c6f263fdfba 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -415,8 +415,10 @@ erc-server-reconnect-attempts
 
 (defcustom erc-server-reconnect-timeout 1
   "Number of seconds to wait between successive reconnect attempts.
-
-If a key is pressed while ERC is waiting, it will stop waiting."
+If this value is too low, servers may reject your initial nick
+request upon reconnecting because they haven't yet noticed that
+your previous connection is dead.  If this happens, try setting
+this value to 120 or greater."
   :type 'number)
 
 (defcustom erc-server-reconnect-function 'erc-server-delayed-reconnect
@@ -427,6 +429,7 @@ erc-server-reconnect-function
 and optionally alter the attempts tally."
   :package-version '(ERC . "5.5")
   :type '(choice (function-item erc-server-delayed-reconnect)
+                 (function-item erc-server-delayed-check-reconnect)
                  function))
 
 (defcustom erc-split-line-length 440
@@ -658,6 +661,30 @@ erc--register-connection
   (run-hooks 'erc--server-post-connect-hook)
   (erc-login))
 
+(defvar erc--server-connect-function #'erc--server-propagate-failed-connection
+  "Function called one second after creating a server process.
+Called with the newly created process just before the opening IRC
+protocol exchange.")
+
+(defun erc--server-propagate-failed-connection (process)
+  "Ensure the PROCESS sentinel runs at least once on early failure.
+Act as a watchdog timer to force `erc-process-sentinel' and its
+finalizers, like `erc-disconnected-hook', to run when PROCESS has
+a status of `failed' after one second.  But only do so when its
+error data is something ERC recognizes.  Print an explanation to
+the server buffer in any case."
+  (when (eq (process-status process) 'failed)
+    (erc-display-message
+     nil 'error (process-buffer process)
+     (format "Process exit status: %S" (process-exit-status process)))
+    (pcase (process-exit-status process)
+      (111
+       (erc-process-sentinel process "failed with code 111\n"))
+      (`(file-error . ,_)
+       (erc-process-sentinel process "failed with code -523\n"))
+      ((rx "tls" (+ nonl) "failed")
+       (erc-process-sentinel process "failed with code -525\n")))))
+
 (defvar erc--server-connect-dumb-ipv6-regexp
   ;; Not for validation (gives false positives).
   (rx bot "[" (group (+ (any xdigit digit ":.")) (? "%" (+ alnum))) "]" eot))
@@ -710,7 +737,9 @@ erc-server-connect
     ;; MOTD line)
     (if (eq (process-status process) 'connect)
         ;; waiting for a non-blocking connect - keep the user informed
-        (erc-display-message nil nil buffer "Opening connection..\n")
+        (progn
+          (erc-display-message nil nil buffer "Opening connection..\n")
+          (run-at-time 1 nil erc--server-connect-function process))
       (message "%s...done" msg)
       (erc--register-connection))))
 
@@ -744,6 +773,78 @@ erc-server-delayed-reconnect
     (with-current-buffer buffer
       (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
+    #'erc--server-reconnect-timeout-double)
+
+(defun erc--server-reconnect-timeout-double (existing)
+  "Double EXISTING timeout, but cap it at 5 minutes."
+  (min 300 (* (or existing erc-server-reconnect-timeout) 2)))
+
+;; This may appear to hang at various places.  It's assumed that when
+;; *Messages* contains "Waiting for socket ..."  or similar, progress
+;; will be made eventually.
+
+(defun erc-server-delayed-check-reconnect (buffer)
+  "Wait for internet connectivity before trying to reconnect.
+BUFFER is the server buffer for the current connection."
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (setq erc--server-reconnect-timeout
+            (funcall erc--server-reconnect-timeout-scale-function
+                     erc--server-reconnect-timeout))
+      (let* ((reschedule (lambda (proc)
+                           (when (buffer-live-p buffer)
+                             (with-current-buffer buffer
+                               (let ((erc-server-reconnect-timeout
+                                      erc--server-reconnect-timeout))
+                                 (delete-process proc)
+                                 (erc-display-message nil 'error buffer
+                                                      "Nobody home...")
+                                 (erc-schedule-reconnect buffer 0))))))
+             (conchk-exp (time-add erc--server-reconnect-timeout-check
+                                   (current-time)))
+             (conchk-timer nil)
+             (conchk (lambda (proc)
+                       (let ((status (process-status proc))
+                             (top (time-less-p conchk-exp (current-time))))
+                         (when (or (not (eq 'connect status)) top)
+                           (cancel-timer conchk-timer))
+                         (when (buffer-live-p buffer)
+                           (cond (top (erc-display-message
+                                       nil 'error buffer
+                                       "Timed out while dialing...")
+                                      (delete-process proc)
+                                      (funcall reschedule proc))
+                                 ((eq 'failed status)
+                                  (funcall reschedule proc)))))))
+             (sentinel (lambda (proc event)
+                         (pcase event
+                           ("open\n"
+                            (run-at-time
+                             nil nil #'send-string proc
+                             (format "PING %d\r\n"
+                                     (time-convert nil 'integer))))
+                           ((or "connection broken by remote peer\n"
+                                (rx bot "failed"))
+                            (funcall reschedule proc)))))
+             (filter (lambda (proc _)
+                       (delete-process proc)
+                       (with-current-buffer buffer
+                         (setq erc--server-reconnect-timeout nil))
+                       (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)))
+              (setq conchk-timer (run-at-time 1 1 conchk proc))
+              (set-process-filter proc filter)
+              (set-process-sentinel proc sentinel))
+          (file-error (funcall reschedule nil)))))))
+
 (defun erc-server-filter-function (process string)
   "The process filter for the ERC server."
   (with-current-buffer (process-buffer process)
@@ -823,11 +924,16 @@ erc-schedule-reconnect
 `erc-server-reconnect-count' by INCR unconditionally."
   (let ((count (and (integerp erc-server-reconnect-attempts)
                     (- erc-server-reconnect-attempts
-                       (cl-incf erc-server-reconnect-count (or incr 1))))))
-    (erc-display-message nil 'error (current-buffer) 'reconnecting
+                       (cl-incf erc-server-reconnect-count (or incr 1)))))
+        (proc (buffer-local-value 'erc-server-process buffer)))
+    (erc-display-message nil 'error buffer 'reconnecting
                          ?m erc-server-reconnect-timeout
                          ?i (if count erc-server-reconnect-count "N")
                          ?n (if count erc-server-reconnect-attempts "A"))
+    (set-process-sentinel proc #'ignore)
+    (set-process-filter proc nil)
+    (delete-process proc)
+    (erc-update-mode-line)
     (setq erc-server-reconnecting nil
           erc--server-reconnect-timer
           (run-at-time erc-server-reconnect-timeout nil
diff --git a/test/lisp/erc/erc-scenarios-base-auto-recon.el b/test/lisp/erc/erc-scenarios-base-auto-recon.el
new file mode 100644
index 00000000000..719cf4e3b5d
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-auto-recon.el
@@ -0,0 +1,140 @@
+;;; erc-scenarios-base-auto-recon.el --- auto-recon scenarios -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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 GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(defun erc-scenarios-base-auto-recon--get-unused-port ()
+  (let ((server (make-network-process :name "*erc-scenarios-base-auto-recon*"
+                                      :host "localhost"
+                                      :service t
+                                      :server t)))
+    (delete-process server)
+    (process-contact server :service)))
+
+;; This demos one possible flavor of intermittent service.
+;; It may end up needing to be marked :unstable.
+(ert-deftest erc-scenarios-base-auto-recon-unavailable ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-server-flood-penalty 0.1)
+       (port (erc-scenarios-base-auto-recon--get-unused-port))
+       (erc--server-reconnect-timeout-scale-function (lambda (_) 1))
+       (erc-server-auto-reconnect t)
+       (erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
+       (expect (erc-d-t-make-expecter))
+       (erc-scenarios-common-dialog "base/reconnect")
+       (dumb-server nil))
+
+    (ert-info ("Dialing fails: nobody home")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (erc-d-t-wait-for 10 (not (erc-server-process-alive)))
+        (erc-d-t-wait-for 10 erc--server-reconnect-timer)
+        (funcall expect 10 "Opening connection")
+        (funcall expect 10 "failed")
+
+        (ert-info ("Reconnect function freezes attempts at 1")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home"))))
+
+    (ert-info ("Service appears")
+      (setq dumb-server (erc-d-run "localhost" port
+                                   'just-eof 'unexpected-disconnect))
+      (with-current-buffer (format "127.0.0.1:%d" port)
+        (funcall expect 10 "server is in debug mode")
+        (should (equal (buffer-name) "FooNet"))))
+
+    (ert-info ("Service interrupted, reconnect starts again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))))
+
+    (ert-info ("Service restored")
+      (delete-process dumb-server)
+      (setq dumb-server (erc-d-run "localhost" port
+                                   'just-eof 'unexpected-disconnect))
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "server is in debug mode")))
+
+    (ert-info ("Service interrupted a third time, reconnect starts yet again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+        (erc-cmd-RECONNECT "cancel")
+        (funcall expect 10 "canceled")))))
+
+;; In this test, a listener accepts but doesn't respond to any messages.
+
+(ert-deftest erc-scenarios-base-auto-recon-no-proto ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-server-flood-penalty 0.1)
+       (erc-scenarios-common-dialog "base/reconnect")
+       (erc-d-auto-pong nil)
+       (dumb-server (erc-d-run "localhost" t 'unexpected-disconnect))
+       (port (process-contact dumb-server :service))
+       (erc--server-reconnect-timeout-scale-function (lambda (_) 1))
+       (erc--server-reconnect-timeout-check 0.5)
+       (erc-server-auto-reconnect t)
+       (erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Session succeeds but cut short")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :full-name "tester")
+        (funcall expect 10 "server is in debug mode")
+        (should (equal (buffer-name) "FooNet"))
+        (erc-d-t-wait-for 10 erc--server-reconnect-timer)
+        (delete-process dumb-server)
+        (funcall expect 10 "failed")
+
+        (ert-info ("Reconnect function freezes attempts at 1")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home")
+          (funcall expect 10 "timed out while dialing")
+          (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+          (funcall expect 10 "nobody home"))))
+
+    (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")))
+
+    (ert-info ("Service interrupted again, reconnect starts again")
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "failed")
+        (funcall expect 10 '(: "reconnecting" (+ nonl) "attempt 1/2"))
+        (erc-cmd-RECONNECT "cancel")
+        (funcall expect 10 "canceled")))))
+
+;;; erc-scenarios-base-auto-recon.el ends here
diff --git a/test/lisp/erc/resources/base/reconnect/just-eof.eld b/test/lisp/erc/resources/base/reconnect/just-eof.eld
new file mode 100644
index 00000000000..c80a39b3170
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/just-eof.eld
@@ -0,0 +1,3 @@
+;; -*- mode: lisp-data; -*-
+((eof 5 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/just-ping.eld b/test/lisp/erc/resources/base/reconnect/just-ping.eld
new file mode 100644
index 00000000000..d57888b42d3
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/just-ping.eld
@@ -0,0 +1,4 @@
+;; -*- mode: lisp-data; -*-
+((ping 20 "PING"))
+
+((eof 10 EOF))
diff --git a/test/lisp/erc/resources/base/reconnect/ping-pong.eld b/test/lisp/erc/resources/base/reconnect/ping-pong.eld
new file mode 100644
index 00000000000..b3d36cf6cec
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/ping-pong.eld
@@ -0,0 +1,6 @@
+;; -*- mode: lisp-data; -*-
+((ping 10 "PING ")
+ (0 "PONG fake"))
+
+((eof 10 EOF))
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld b/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld
new file mode 100644
index 00000000000..386d0f4b085
--- /dev/null
+++ b/test/lisp/erc/resources/base/reconnect/unexpected-disconnect.eld
@@ -0,0 +1,24 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 NETWORK=FooNet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
+
+((drop 0 DROP))
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el
index 0d9a79ae9ce..f259c88594b 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -121,6 +121,7 @@ erc-scenarios-common--print-trace
       (erc-modules (copy-sequence erc-modules))
       (inhibit-interaction t)
       (auth-source-do-cache nil)
+      (timer-list (copy-sequence timer-list))
       (erc-auth-source-parameters-join-function nil)
       (erc-autojoin-channels-alist nil)
       (erc-server-auto-reconnect nil)
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]             ` <87v8j715om.fsf@neverwas.me>
@ 2023-04-10 20:25               ` J.P.
  0 siblings, 0 replies; 12+ messages in thread
From: J.P. @ 2023-04-10 20:25 UTC (permalink / raw)
  To: xoddf2; +Cc: emacs-erc, 62044

A Libera user was good enough to try this patch and has unfortunately
reported something reminiscent of the old buffer-association troubles
from versions past. According to them, buffers aren't being reused and
new ones are receiving "<n>"-suffixed names. Sadly, this sounds all too
plausible, although they haven't yet furnished a recipe, and I haven't
been able to reproduce anything similar.

Despite this, I've decided to keep things moving and perhaps cast a
wider net by adding these changes to HEAD. Hopefully, this will compel
others to shed more light on the user's account. If all else fails, I
suppose we can consider temporarily changing the default value of
`erc-server-reconnect-function' to enable the new behavior for everyone.
Of course, that runs the risk of annoying disinterested folks while we
work out the kinks. If anyone has something to add here, please share.
Thanks.





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: Status update?
  2023-03-08  6:12 bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken xoddf2
  2023-03-08  7:56 ` J.P.
       [not found] ` <87pm9jy8v7.fsf@neverwas.me>
@ 2024-04-29  9:56 ` Alexis
  2024-05-03  2:32   ` bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken J.P.
       [not found]   ` <87wmoby69b.fsf@neverwas.me>
  2 siblings, 2 replies; 12+ messages in thread
From: Alexis @ 2024-04-29  9:56 UTC (permalink / raw)
  To: 62044; +Cc: emacs-erc


i'm also affected by this issue, as a user of the soju 
bouncer. i'm on Emacs 29.3.

i using ERC on my laptop, and my network connection is frequently 
disconnected and reconnected: partly because i'm regularly moving 
around, but also due to occasional dropouts on my home network.

Is there anything i might be able to do to help with this? #29 
says that certain changes have been added to HEAD; should i apply 
those changes and report back what, if anything, i discover?





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
  2024-04-29  9:56 ` bug#62044: Status update? Alexis
@ 2024-05-03  2:32   ` J.P.
       [not found]   ` <87wmoby69b.fsf@neverwas.me>
  1 sibling, 0 replies; 12+ messages in thread
From: J.P. @ 2024-05-03  2:32 UTC (permalink / raw)
  To: Alexis; +Cc: emacs-erc, 62044

Hi Alexis,

Alexis <flexibeast@gmail.com> writes:

> i'm also affected by this issue, as a user of the soju bouncer. i'm on Emacs
> 29.3.
>
> i using ERC on my laptop, and my network connection is frequently disconnected
> and reconnected: partly because i'm regularly moving around, but also due to
> occasional dropouts on my home network.
>
> Is there anything i might be able to do to help with this? #29 says that
> certain changes have been added to HEAD; should i apply those changes and
> report back what, if anything, i discover?

Yes, please install ERC 5.6 when it's released, which should be any day
now. If you can't wait, you can try out the devel version [1]. Either
way, make sure to customize the option `erc-server-reconnect-function'
to `erc-server-delayed-check-reconnect' before connecting. Note that not
all values of `erc-server-connect-function' are supported. And yes, if
you could report back with any findings, that'd be great.

Thanks,
J.P.

[1] https://elpa.gnu.org/devel/doc/erc.html#Upgrading





^ permalink raw reply	[flat|nested] 12+ messages in thread

* bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken
       [not found]   ` <87wmoby69b.fsf@neverwas.me>
@ 2024-05-09  6:13     ` Alexis
  0 siblings, 0 replies; 12+ messages in thread
From: Alexis @ 2024-05-09  6:13 UTC (permalink / raw)
  To: J.P.; +Cc: emacs-erc, 62044

"J.P." <jp@neverwas.me> writes:

> Yes, please install ERC 5.6 when it's released, which should be 
> any day
> now. If you can't wait, you can try out the devel version 
> [1]. Either
> way, make sure to customize the option 
> `erc-server-reconnect-function'
> to `erc-server-delayed-check-reconnect' before connecting. Note 
> that not
> all values of `erc-server-connect-function' are supported. And 
> yes, if
> you could report back with any findings, that'd be great.

Ah okay, thanks - i'll keep an eye out for the release, and let 
you know what i find. :-)


Alexis.





^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2024-05-09  6:13 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-08  6:12 bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken xoddf2
2023-03-08  7:56 ` J.P.
     [not found] ` <87pm9jy8v7.fsf@neverwas.me>
2023-03-08  9:07   ` xoddf2
     [not found]   ` <87sfefr4qa.fsf@gmail.com>
2023-03-08 16:12     ` J.P.
     [not found]     ` <878rg7ql29.fsf@neverwas.me>
2023-03-09  2:22       ` J.P.
     [not found]       ` <87fsaepsso.fsf@neverwas.me>
2023-03-09 14:38         ` J.P.
     [not found]         ` <87lek6kn1b.fsf@neverwas.me>
2023-03-10  7:34           ` xoddf2
     [not found]           ` <87zg8lawlk.fsf@gmail.com>
2023-03-11 18:52             ` J.P.
     [not found]             ` <87v8j715om.fsf@neverwas.me>
2023-04-10 20:25               ` J.P.
2024-04-29  9:56 ` bug#62044: Status update? Alexis
2024-05-03  2:32   ` bug#62044: 30.0.50; ERC 5.5: Auto-reconnect is broken J.P.
     [not found]   ` <87wmoby69b.fsf@neverwas.me>
2024-05-09  6:13     ` Alexis

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).