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);
}
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;
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);
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;
}
}
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.
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.
*
*/
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)
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);
}