]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
listen: disarm the timers when closing a virtual listener developer/arr2036 master
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 28 Jul 2026 01:07:22 +0000 (19:07 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 28 Jul 2026 01:20:51 +0000 (19:20 -0600)
proto_load_step and proto_cron_crontab drive themselves from timers rather than from their fd, and neither had a close callback, so nothing stopped them when the listener was closed. The load generator kept manufacturing packets and handing them to fr_network_send_request() after the network had signalled the workers to close, which the assert added there caught.

Both now close the fd and remove their timer.  Of the remaining app_io modules with timers, proto_detail_file, proto_detail_work and proto_ldap_sync_ldap have a close callback that does not obviously disarm anything, and are worth a look.

src/listen/cron/proto_cron_crontab.c
src/listen/load/proto_load_step.c

index 7459bd891bb04e255cc1a208bf08c3d4168dde09..4d1bfabfee1fe8f1fda1165f6636deb8f6b9488b 100644 (file)
@@ -653,6 +653,31 @@ use_time:
        fr_network_listen_read(thread->nr, thread->parent);
 }
 
        fr_network_listen_read(thread->nr, thread->parent);
 }
 
+/** Close a virtual listener
+ *
+ * The fd only exists to bootstrap the listener, so closing it mostly means
+ * removing the timer that runs the jobs.
+ *
+ * @param[in] li the listener
+ * @return
+ *     - 0 on success.
+ *     - -1 if the timer could not be deleted.  The fd is closed either way.
+ */
+static int mod_close(fr_listen_t *li)
+{
+       proto_cron_crontab_thread_t     *thread = talloc_get_type_abort(li->thread_instance, proto_cron_crontab_thread_t);
+       int                             ret = 0;
+
+       if (thread->ev && (fr_timer_delete(&thread->ev) < 0)) {
+               PERROR("Failed deleting cron timer");
+               ret = -1;
+       }
+
+       close(li->fd);
+
+       return ret;
+}
+
 /** Set the event list for a new socket
  *
  * @param[in] li the listener
 /** Set the event list for a new socket
  *
  * @param[in] li the listener
@@ -748,6 +773,7 @@ fr_app_io_t proto_cron_crontab = {
        .track_duplicates       = false,
 
        .open                   = mod_open,
        .track_duplicates       = false,
 
        .open                   = mod_open,
+       .close                  = mod_close,
        .read                   = mod_read,
        .write                  = mod_write,
        .event_list_set         = mod_event_list_set,
        .read                   = mod_read,
        .write                  = mod_write,
        .event_list_set         = mod_event_list_set,
index 763d361486fa35dac02fdf0a1ac3f777bede1eee..60f8f613668d0aef08e1f67c83b0072a6423e504 100644 (file)
@@ -356,6 +356,31 @@ static int mod_decode(void const *instance, request_t *request, UNUSED uint8_t *
        return 0;
 }
 
        return 0;
 }
 
+/** Close a virtual listener
+ *
+ * The fd only exists to bootstrap the listener, so closing it mostly means
+ * removing the timer that drives the load generator.
+ *
+ * @param[in] li the listener
+ * @return
+ *     - 0 on success.
+ *     - -1 if the generator could not be stopped.  The fd is closed either way.
+ */
+static int mod_close(fr_listen_t *li)
+{
+       proto_load_step_thread_t        *thread = talloc_get_type_abort(li->thread_instance, proto_load_step_thread_t);
+       int                             ret = 0;
+
+       if (thread->l && (fr_load_generator_stop(thread->l) < 0)) {
+               PERROR("Failed stopping load generator");
+               ret = -1;
+       }
+
+       close(li->fd);
+
+       return ret;
+}
+
 /** Set the event list for a new socket
  *
  * @param[in] li the listener
 /** Set the event list for a new socket
  *
  * @param[in] li the listener
@@ -506,6 +531,7 @@ fr_app_io_t proto_load_step = {
        .track_duplicates       = false,
 
        .open                   = mod_open,
        .track_duplicates       = false,
 
        .open                   = mod_open,
+       .close                  = mod_close,
        .read                   = mod_read,
        .write                  = mod_write,
        .event_list_set         = mod_event_list_set,
        .read                   = mod_read,
        .write                  = mod_write,
        .event_list_set         = mod_event_list_set,