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/acronc/handler_socket.c | 66 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 33 deletions(-) (limited to 'client/acronc/handler_socket.c') diff --git a/client/acronc/handler_socket.c b/client/acronc/handler_socket.c index 2dfda5e..c0a9923 100644 --- a/client/acronc/handler_socket.c +++ b/client/acronc/handler_socket.c @@ -125,50 +125,50 @@ static void on_read(uv_stream_t *tcp, ssize_t nread, const uv_buf_t *buf) { } int r; ac_obj_t *obj = NULL; - if ((r = ac_receive(ac_conn, buf->base, nread, &obj))) { - LOGEV("Cannot parse the response (%d).", r); - /* libac error. Socket is working. */ - ex(false); - return; - } - - if (!ready) { - enum ac_connection_state state; - if ((r = ac_get_state(ac_conn, &state))) { - LOGEV("Cannot get state (%d).", r); + size_t pos = 0; + size_t read = 0; + bool again = false; + while (read < nread || again) { + if (again) { + LOGD("Clearing backlog."); + r = ac_receive(ac_conn, NULL, 0, 0, &obj, NULL); + again = false; + } else { + r = ac_receive(ac_conn, buf->base, pos, nread, &obj, &read); + pos += read; + } + if (r == AC_E_AGAIN) { + again = true; + } else if (r) { + LOGEV("Cannot parse the response (%d).", r); /* libac error. Socket is working. */ ex(false); + free(buf->base); return; } - if (state == AC_STATE_READY) { - ready = true; - if ((cb_ready())) { - /* acronc error. Socket is working. */ - ex(false); - return; - } - } - } - if (obj) { - LOGDV("Got object: %p", obj); - /* uv_async_send is unreliable, and missed messages will cause memory leak. */ - if (cb_recv(obj)) { - /* acronc error. Socket is working. */ - ex(false); - } - LOGD("Clearing backlog."); - while (true) { - if ((r = ac_receive(ac_conn, NULL, 0, &obj))) { - LOGEV("Cannot clear backlog (%d).", r); + if (!ready) { + enum ac_connection_state state; + if ((r = ac_get_state(ac_conn, &state))) { + LOGEV("Cannot get state (%d).", r); /* libac error. Socket is working. */ free(buf->base); ex(false); return; } - if (!obj) { - break; + if (state == AC_STATE_READY) { + ready = true; + if ((cb_ready())) { + /* acronc error. Socket is working. */ + free(buf->base); + ex(false); + return; + } } + } + if (obj) { + LOGDV("Got object: %p", obj); + /* uv_async_send is unreliable, and missed messages will cause memory leak. */ if (cb_recv(obj)) { /* acronc error. Socket is working. */ ex(false); -- cgit v1.2.3