From 7edaa14c2c822e5b776edaa6534753b258d29488 Mon Sep 17 00:00:00 2001 From: Trumeet Date: Tue, 9 Aug 2022 17:15:45 -0700 Subject: fix(libacron): infinite loop when wic_parse returns 0 This is a rather complicated way to fix backlogging issues. It asks the client to pass partial buffer, and the client also must retry with NULL buffer if ac_receive returns AC_E_AGAIN. --- client/helloworld/main.c | 92 ++++++++++++++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 34 deletions(-) (limited to 'client/helloworld/main.c') diff --git a/client/helloworld/main.c b/client/helloworld/main.c index 8b3486b..079b957 100644 --- a/client/helloworld/main.c +++ b/client/helloworld/main.c @@ -74,6 +74,8 @@ return 0; \ #endif +static bool ready = false; + static const char *world_name(const enum ac_world world) { switch (world) { case overworld: @@ -227,6 +229,39 @@ static int say(void *connection) { return 0; } +static int process(void *connection, ac_obj_t *obj) { + int r; + if (!ready) { + /* Wait until ready. */ + enum ac_connection_state state; + if ((r = ac_get_state(connection, &state))) { + return r; + } + switch (state) { + case AC_STATE_INIT: + return 0; + case AC_STATE_READY: + printf("Connection is established.\n"); + ready = true; + say(connection); + return 0; + default: + fprintf(stderr, "Unexpected state.\n"); + return 1; + } + } + if (!obj) { + return 0; + } + if (AC_IS_EVENT(obj->type)) { + handle_event((ac_event_t *) obj); + } else if (AC_IS_RESPONSE(obj->type)) { + handle_response((ac_response_t *) obj); + } + ac_object_free(obj); + return 0; +} + int main(int argc, char **argv) { int r; if ((r = net_init())) { @@ -299,11 +334,12 @@ int main(int argc, char **argv) { ac_obj_t *obj; int nr; uint8_t buffer[1000U]; - size_t bytes; - enum ac_connection_state state; printf("Waiting until the connection is established.\n"); - bool ready = false; + bool again = false; while (1) { + size_t read = 0; + size_t pos = 0; + size_t bytes; if ((nr = net_read(&sock, buffer, sizeof(buffer), &bytes, 10))) { if (nr == NET_TIMEOUT) { printf("Receive timeout.\n"); @@ -313,42 +349,30 @@ int main(int argc, char **argv) { } } if ((r = lock())) { goto end; } - if ((r = ac_receive(connection, buffer, bytes, &obj))) { - if ((r = unlock())) { goto end; } - goto end; - } - if (!ready) { - /* Wait until ready. */ - if ((r = ac_get_state(connection, &state))) { - if ((r = unlock())) { goto end; } + if ((r = ac_receive(connection, buffer, pos, bytes, &obj, &read))) { + bool again = r == AC_E_AGAIN; + if (!again) { + unlock(); goto end; } - switch (state) { - case AC_STATE_INIT: - continue; - case AC_STATE_READY: - printf("Connection is established.\n"); - ready = true; - say(connection); - if ((r = unlock())) { goto end; } - continue; - default: - fprintf(stderr, "Unexpected state.\n"); - if ((r = unlock())) { goto end; } - goto end; - } } + r = process(connection, obj); if ((r = unlock())) { goto end; } - - if (!obj) { - continue; - } - if (AC_IS_EVENT(obj->type)) { - handle_event((ac_event_t *) obj); - } else if (AC_IS_RESPONSE(obj->type)) { - handle_response((ac_response_t *) obj); + if (r) { goto end; } + while (!again) { + if ((r = lock())) { goto end; } + if ((r = ac_receive(connection, NULL, 0, 0, &obj, NULL))) { + bool again = r == AC_E_AGAIN; + if (!again) { + unlock(); + goto end; + } + } + again = false; + r = process(connection, obj); + if ((r = unlock())) { goto end; } + if (r) { goto end; } } - ac_object_free(obj); } end: if (nr) { -- cgit v1.2.3