From 4af13b96aba53d0db1dcc6543e70ee74ccc7e2d6 Mon Sep 17 00:00:00 2001 From: Vadzim Dambrouski Date: Fri, 19 Jun 2026 20:32:20 +0200 Subject: [PATCH] xvc_client: block until full reply received, fixes errors on a slow network ll_write() can request more than 1.5K of data, but recv() call will return right away as soon as one packet is received. This causes large transfers to break as not enough data is received. Fixed by adding rx_exact flag and enabled it for ll_write() Tested with Zynq7010 on a slow WiFi. Before the patch all uploads were silently failing with no error in the log. Signed-off-by: Vadzim Dambrouski --- src/xvc_client.cpp | 28 +++++++++++++++++++++++++--- src/xvc_client.hpp | 3 ++- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/xvc_client.cpp b/src/xvc_client.cpp index 8d6f38d..0665e4f 100644 --- a/src/xvc_client.cpp +++ b/src/xvc_client.cpp @@ -261,9 +261,26 @@ int sendall(int sock, const void* raw, size_t cnt, int flags) return cnt; // success } +static +ssize_t recvall(int sock, void* raw, size_t cnt, int flags) +{ + char *buf = (char*)raw; + size_t remaining = cnt; + while (remaining) { + ssize_t ret = recv(sock, buf, remaining, flags); + if (ret < 0) + return ret; + if (ret == 0) // peer closed the connection mid-reply + break; + buf += ret; + remaining -= ret; + } + return cnt - remaining; +} + ssize_t XVC_client::xfer_pkt(const std::string &instr, const uint8_t *tx, uint32_t tx_size, - uint8_t *rx, uint32_t rx_size) + uint8_t *rx, uint32_t rx_size, bool rx_exact) { ssize_t len = tx_size; std::vector buffer(instr.size() + ((tx) ? tx_size : 0)); @@ -277,9 +294,14 @@ ssize_t XVC_client::xfer_pkt(const std::string &instr, } if (rx) { - len = recv(_sock, rx, rx_size, 0); + if (rx_exact) { + len = recvall(_sock, rx, rx_size, 0); + } else { + len = recv(_sock, rx, rx_size, 0); + } if (len < 0) { printError("Receive error"); + return len; } else if (len == 0) { fprintf(stderr, "Client orderly shut down the connection.\n"); } @@ -312,7 +334,7 @@ bool XVC_client::ll_write(uint8_t *tdo) memcpy(_xfer_buf + 4 + numbytes, _tditdo, numbytes); if ((ret = xfer_pkt("shift:\0", _xfer_buf, (2 * numbytes) + 4, - _tditdo, numbytes)) < 0) + _tditdo, numbytes, true)) < 0) return false; _num_bits = 0; // clear counter diff --git a/src/xvc_client.hpp b/src/xvc_client.hpp index 9bd7169..bbb0789 100644 --- a/src/xvc_client.hpp +++ b/src/xvc_client.hpp @@ -95,11 +95,12 @@ class XVC_client: public JtagInterface { * \param[in] tx_size: tx size (in Byte) * \param[in] rx: server answer buffer (may be NULL) * \param[in] rx_size: rx size (in Byte) or (0 when unused) + * \param[in] rx_exact: block until exactly rx_size bytes received * \return -1 when error, 0 when disconnected or tx_size/rx_size */ ssize_t xfer_pkt(const std::string &instr, const uint8_t *tx, uint32_t tx_size, - uint8_t *rx, uint32_t rx_size); + uint8_t *rx, uint32_t rx_size, bool rx_exact = false); /*! * \brief lowlevel write: EMU_CMD_HW_JTAGx implementation