diff mbox series

[ovs-dev,2/5] jsonrpc: Add _until variants of recv functions.

Message ID 20250507134151.118615-3-martin.morgenstern@cloudandheat.com
State New
Delegated to: Ilya Maximets
Headers show
Series Timing API for jsonrpc, ovsdb-cs and ovsdb-idl. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Martin Morgenstern May 7, 2025, 1:41 p.m. UTC
Add a timing based variant of jsonrpc_recv() and jsonrpc_session_recv()
(suffixed with '_until').

These new functions have an additional 'deadline' parameter and will
attempt to receive JSON-RPC messages until either a complete message
is received or the deadline is reached.

Signed-off-by: Martin Morgenstern <martin.morgenstern@cloudandheat.com>
---
 lib/jsonrpc.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++--
 lib/jsonrpc.h |  3 +++
 2 files changed, 63 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c
index a352e01fb..c2bd72408 100644
--- a/lib/jsonrpc.c
+++ b/lib/jsonrpc.c
@@ -443,6 +443,54 @@  jsonrpc_recv(struct jsonrpc *rpc, struct jsonrpc_msg **msgp)
     return EAGAIN;
 }
 
+/* Attempts to receive a message from 'rpc' until either a complete message
+ * is received or the given deadline has passed.
+ *
+ * If successful, stores the received message in '*msgp' and returns 0.  The
+ * caller takes ownership of '*msgp' and must eventually destroy it with
+ * jsonrpc_msg_destroy().
+ *
+ * Otherwise, stores NULL in '*msgp' and returns one of the following:
+ *
+ *   - EAGAIN: No message has been received (e.g., if the underlying stream
+ *     blocks).
+ *
+ *   - ETIME: The deadline passed and we could not receive a complete message
+ *     in the meantime.
+ *
+ *   - EOF: The remote end closed the connection gracefully.
+ *
+ *   - Otherwise an errno value that represents a JSON-RPC protocol violation
+ *     or another error fatal to the connection.  'rpc' will not send or
+ *     receive any more messages.
+ */
+int
+jsonrpc_recv_until(struct jsonrpc *rpc, struct jsonrpc_msg **msgp,
+                   long long deadline)
+{
+    *msgp = NULL;
+    if (rpc->status) {
+        return rpc->status;
+    }
+
+    while (time_msec() < deadline) {
+        int retval = jsonrpc_recv_chunk(rpc);
+        if (retval) {
+            return retval;
+        }
+        retval = jsonrpc_get_message(rpc, msgp);
+        if (retval != ENODATA) {
+            return retval;
+        }
+    }
+
+    /* We tried hard but didn't get a complete JSON message before the given
+     * deadline.  We want to know how often we abort for this reason. */
+    COVERAGE_INC(jsonrpc_recv_incomplete);
+
+    return ETIME;
+}
+
 /* Causes the poll loop to wake up when jsonrpc_recv() may return a value other
  * than EAGAIN. */
 void
@@ -1222,14 +1270,18 @@  jsonrpc_session_send(struct jsonrpc_session *s, struct jsonrpc_msg *msg)
 }
 
 struct jsonrpc_msg *
-jsonrpc_session_recv(struct jsonrpc_session *s)
+jsonrpc_session_recv_until(struct jsonrpc_session *s, long long deadline)
 {
     if (s->rpc) {
         unsigned int received_bytes;
         struct jsonrpc_msg *msg;
 
         received_bytes = jsonrpc_get_received_bytes(s->rpc);
-        jsonrpc_recv(s->rpc, &msg);
+        if (deadline) {
+            jsonrpc_recv_until(s->rpc, &msg, deadline);
+        } else {
+            jsonrpc_recv(s->rpc, &msg);
+        }
 
         long long int now = time_msec();
         reconnect_receive_attempted(s->reconnect, now);
@@ -1262,6 +1314,12 @@  jsonrpc_session_recv(struct jsonrpc_session *s)
     return NULL;
 }
 
+struct jsonrpc_msg *
+jsonrpc_session_recv(struct jsonrpc_session *s)
+{
+    return jsonrpc_session_recv_until(s, 0);
+}
+
 void
 jsonrpc_session_recv_wait(struct jsonrpc_session *s)
 {
diff --git a/lib/jsonrpc.h b/lib/jsonrpc.h
index 1baffcd80..09a4b0fd1 100644
--- a/lib/jsonrpc.h
+++ b/lib/jsonrpc.h
@@ -59,6 +59,7 @@  const char *jsonrpc_get_name(const struct jsonrpc *);
 
 int jsonrpc_send(struct jsonrpc *, struct jsonrpc_msg *);
 int jsonrpc_recv(struct jsonrpc *, struct jsonrpc_msg **);
+int jsonrpc_recv_until(struct jsonrpc *, struct jsonrpc_msg **, long long);
 void jsonrpc_recv_wait(struct jsonrpc *);
 
 int jsonrpc_send_block(struct jsonrpc *, struct jsonrpc_msg *);
@@ -125,6 +126,8 @@  size_t jsonrpc_session_get_n_remotes(const struct jsonrpc_session *);
 
 int jsonrpc_session_send(struct jsonrpc_session *, struct jsonrpc_msg *);
 struct jsonrpc_msg *jsonrpc_session_recv(struct jsonrpc_session *);
+struct jsonrpc_msg *jsonrpc_session_recv_until(struct jsonrpc_session *,
+                                               long long);
 void jsonrpc_session_recv_wait(struct jsonrpc_session *);
 
 bool jsonrpc_session_is_alive(const struct jsonrpc_session *);