]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
more gluing in of EOF callbacks
authorAlan T. DeKok <aland@freeradius.org>
Thu, 6 Jun 2024 13:43:58 +0000 (09:43 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 6 Jun 2024 16:43:07 +0000 (12:43 -0400)
src/bin/radclient-ng.c
src/lib/bio/base.h
src/lib/bio/fd.c
src/lib/bio/fd_errno.h
src/protocols/radius/client.c

index e6dede015315c32d977d2a7cea1559c7f56da102..7da8f4c08e8bf598962e27c9087a67046b89a7a8 100644 (file)
@@ -1099,9 +1099,18 @@ static int client_bio_write_resume(fr_bio_packet_t *bio)
 
 
 static NEVER_RETURNS void client_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags,
-                                      int fd_errno, UNUSED void *uctx)
+                                      int fd_errno, void *uctx)
 {
+       fr_bio_packet_t *client = uctx;
+
        ERROR("Failed in connection - %s", fr_syserror(fd_errno));
+
+       /*
+        *      Cleanly close the BIO, so that we exercise the shutdown path.
+        */
+       fr_assert(client == client_bio);
+       TALLOC_FREE(client_bio);
+
        fr_exit_now(1);
 }
 
index 56aa564ffa20dd9bb1f2eb7e2308783551ced53a..0f00397e956faa2eb4faa0262fb5654dae7fc3a3 100644 (file)
@@ -85,6 +85,7 @@ typedef void (*fr_bio_callback_t)(fr_bio_t *bio); /* activate / shutdown callbac
 
 typedef struct {
        fr_bio_callback_t       activate;               //!< called when the BIO is ready to be used
+       fr_bio_callback_t       eof;                    //!< called when the BIO is at EOF
        fr_bio_callback_t       shutdown;               //!< called when the BIO is being shut down
 
        fr_bio_io_t             read_blocked;
index 4c142019c4922c6e245b20f138ae1f7f5f514140..7557e88ef96a365b87bd452dcc565c0b5ad3a8d0 100644 (file)
@@ -100,6 +100,8 @@ static int fr_bio_fd_destructor(fr_bio_fd_t *my)
        fr_assert(!fr_bio_prev(&my->bio));
        fr_assert(!fr_bio_next(&my->bio));
 
+       if (!my->info.eof && my->cb.eof) my->cb.eof(&my->bio);
+
        if (my->cb.shutdown) my->cb.shutdown(&my->bio);
 
        return fr_bio_fd_close(&my->bio);
@@ -130,6 +132,7 @@ retry:
        rcode = read(my->info.socket.fd, buffer, size);
        if (rcode == 0) {
                fr_bio_eof(bio);
+               if (my->cb.eof) my->cb.eof(&my->bio); /* inform the application that we're at EOF */
                return 0;
        }
 
index a33416243520a2a659599bfe58d20a01a23fdc60..7f58e0eb499ce907772e40447ee9ae737d1bea7a 100644 (file)
@@ -27,6 +27,26 @@ case EAGAIN:
        }
        return fr_bio_error(IO_WOULD_BLOCK);
 
+#ifndef NDEBUG
+case ENOTCONN:
+       /*
+        *      We're doing a read/write to a socket which isn't connected.  This is a failure of the
+        *      application state machine.
+        */
+       fr_assert(0);
+       break;
+#endif
+
+case ECONNRESET:
+case EPIPE:
+       /*
+        *      The other end closed the connection, signal the application that it's a (maybe) clean close,
+        *      and set EOF on the BIO.
+        */
+       fr_bio_eof(&my->bio);
+       if (my->cb.eof) my->cb.eof(&my->bio); /* inform the application that we're at EOF */
+       return 0;
+
 default:
        /*
         *      Some other error, it's fatal.
index 88d6d26a3638aef2dc3d1d6bef569bedabb977d5..0c90587617c428fe49555fb4c3c21dd9099eb208 100644 (file)
@@ -623,6 +623,13 @@ int fr_radius_client_bio_force_id(fr_bio_packet_t *bio, int code, int id)
        return fr_radius_code_id_force(my->codes, code, id);
 }
 
+static void fr_radius_client_bio_eof(fr_bio_t *bio)
+{
+       fr_radius_client_fd_bio_t *my = bio->uctx;
+
+       if (my->common.cb.eof) my->common.cb.eof(&my->common);
+}
+
 /** Callback for when the FD is activated, i.e. connected.
  *
  */
@@ -633,8 +640,6 @@ static void fr_radius_client_bio_activate(fr_bio_t *bio)
        fr_assert(!my->info.connected);
 
        my->info.connected = true;
-
-       fr_assert(0);
 }
 
 void fr_radius_client_bio_connect(NDEBUG_UNUSED fr_event_list_t *el, NDEBUG_UNUSED int fd, UNUSED int flags, void *uctx)
@@ -782,7 +787,12 @@ void fr_radius_client_bio_cb_set(fr_bio_packet_t *bio, fr_bio_packet_cb_funcs_t
 
        my->common.cb = *cb;
 
-       fr_bio_cb_set(my->fd, &bio_cb);
        fr_bio_cb_set(my->mem, &bio_cb);
        fr_bio_cb_set(my->retry, &bio_cb);
+
+       /*
+        *      Only the FD bio gets an EOF callback.
+        */
+       bio_cb.eof = fr_radius_client_bio_eof;
+       fr_bio_cb_set(my->fd, &bio_cb);
 }