aboutsummaryrefslogtreecommitdiff
path: root/src/mpack/rpc.c
diff options
context:
space:
mode:
authorBjörn Linse <bjorn.linse@gmail.com>2021-09-04 16:59:26 +0200
committerBjörn Linse <bjorn.linse@gmail.com>2021-09-09 16:06:43 +0200
commitc8f46480bc0bfd07c8a69d61e365706e3184abc9 (patch)
treeed0f91460fc3988bb7efd5aea24c9a037c418f07 /src/mpack/rpc.c
parentd8339be6915b3640f12a1827cee652b604b1a0d7 (diff)
downloadrneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.gz
rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.tar.bz2
rneovim-c8f46480bc0bfd07c8a69d61e365706e3184abc9.zip
build: vendor libmpack source from libmpack/libmpack 22b1fd90285117c995728511f9525d29520a8c82
Diffstat (limited to 'src/mpack/rpc.c')
-rw-r--r--src/mpack/rpc.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/mpack/rpc.c b/src/mpack/rpc.c
new file mode 100644
index 0000000000..3b2b328065
--- /dev/null
+++ b/src/mpack/rpc.c
@@ -0,0 +1,331 @@
+#include <string.h>
+
+#include "rpc.h"
+
+enum {
+ MPACK_RPC_RECEIVE_ARRAY = 1,
+ MPACK_RPC_RECEIVE_TYPE,
+ MPACK_RPC_RECEIVE_ID
+};
+
+static mpack_rpc_header_t mpack_rpc_request_hdr(void);
+static mpack_rpc_header_t mpack_rpc_reply_hdr(void);
+static mpack_rpc_header_t mpack_rpc_notify_hdr(void);
+static int mpack_rpc_put(mpack_rpc_session_t *s, mpack_rpc_message_t m);
+static int mpack_rpc_pop(mpack_rpc_session_t *s, mpack_rpc_message_t *m);
+static void mpack_rpc_reset_hdr(mpack_rpc_header_t *hdr);
+
+MPACK_API void mpack_rpc_session_init(mpack_rpc_session_t *session,
+ mpack_uint32_t capacity)
+{
+ session->capacity = capacity ? capacity : MPACK_RPC_MAX_REQUESTS;
+ session->request_id = 0;
+ mpack_tokbuf_init(&session->reader);
+ mpack_tokbuf_init(&session->writer);
+ mpack_rpc_reset_hdr(&session->receive);
+ mpack_rpc_reset_hdr(&session->send);
+ memset(session->slots, 0,
+ sizeof(struct mpack_rpc_slot_s) * session->capacity);
+}
+
+MPACK_API int mpack_rpc_receive_tok(mpack_rpc_session_t *session,
+ mpack_token_t tok, mpack_rpc_message_t *msg)
+{
+ int type;
+
+ if (session->receive.index == 0) {
+ if (tok.type != MPACK_TOKEN_ARRAY)
+ /* not an array */
+ return MPACK_RPC_EARRAY;
+
+ if (tok.length < 3 || tok.length > 4)
+ /* invalid array length */
+ return MPACK_RPC_EARRAYL;
+
+ session->receive.toks[0] = tok;
+ session->receive.index++;
+ return MPACK_EOF; /* get the type */
+ }
+
+ if (session->receive.index == 1) {
+
+ if (tok.type != MPACK_TOKEN_UINT || tok.length > 1 || tok.data.value.lo > 2)
+ /* invalid type */
+ return MPACK_RPC_ETYPE;
+
+ if (tok.data.value.lo < 2 && session->receive.toks[0].length != 4)
+ /* request or response with array length != 4 */
+ return MPACK_RPC_EARRAYL;
+
+ if (tok.data.value.lo == 2 && session->receive.toks[0].length != 3)
+ /* notification with array length != 3 */
+ return MPACK_RPC_EARRAYL;
+
+ session->receive.toks[1] = tok;
+ session->receive.index++;
+
+ if (tok.data.value.lo < 2) return MPACK_EOF;
+
+ type = MPACK_RPC_NOTIFICATION;
+ goto end;
+ }
+
+ assert(session->receive.index == 2);
+
+ if (tok.type != MPACK_TOKEN_UINT || tok.length > 4)
+ /* invalid request/response id */
+ return MPACK_RPC_EMSGID;
+
+ msg->id = tok.data.value.lo;
+ msg->data.p = NULL;
+ type = (int)session->receive.toks[1].data.value.lo + MPACK_RPC_REQUEST;
+
+ if (type == MPACK_RPC_RESPONSE && !mpack_rpc_pop(session, msg))
+ /* response with invalid id */
+ return MPACK_RPC_ERESPID;
+
+end:
+ mpack_rpc_reset_hdr(&session->receive);
+ return type;
+}
+
+MPACK_API int mpack_rpc_request_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok, mpack_data_t data)
+{
+ if (session->send.index == 0) {
+ int status;
+ mpack_rpc_message_t msg;
+ do {
+ msg.id = session->request_id;
+ msg.data = data;
+ session->send = mpack_rpc_request_hdr();
+ session->send.toks[2].type = MPACK_TOKEN_UINT;
+ session->send.toks[2].data.value.lo = msg.id;
+ session->send.toks[2].data.value.hi = 0;
+ *tok = session->send.toks[0];
+ status = mpack_rpc_put(session, msg);
+ if (status == -1) return MPACK_NOMEM;
+ session->request_id = (session->request_id + 1) % 0xffffffff;
+ } while (!status);
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ if (session->send.index == 1) {
+ *tok = session->send.toks[1];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 2);
+ *tok = session->send.toks[2];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_reply_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok, mpack_uint32_t id)
+{
+ if (session->send.index == 0) {
+ session->send = mpack_rpc_reply_hdr();
+ session->send.toks[2].type = MPACK_TOKEN_UINT;
+ session->send.toks[2].data.value.lo = id;
+ session->send.toks[2].data.value.hi = 0;
+ *tok = session->send.toks[0];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ if (session->send.index == 1) {
+ *tok = session->send.toks[1];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 2);
+ *tok = session->send.toks[2];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_notify_tok(mpack_rpc_session_t *session,
+ mpack_token_t *tok)
+{
+ if (session->send.index == 0) {
+ session->send = mpack_rpc_notify_hdr();
+ *tok = session->send.toks[0];
+ session->send.index++;
+ return MPACK_EOF;
+ }
+
+ assert(session->send.index == 1);
+ *tok = session->send.toks[1];
+ mpack_rpc_reset_hdr(&session->send);
+ return MPACK_OK;
+}
+
+MPACK_API int mpack_rpc_receive(mpack_rpc_session_t *session, const char **buf,
+ size_t *buflen, mpack_rpc_message_t *msg)
+{
+ int status;
+
+ do {
+ mpack_token_t tok;
+ status = mpack_read(&session->reader, buf, buflen, &tok);
+ if (status) break;
+ status = mpack_rpc_receive_tok(session, tok, msg);
+ if (status >= MPACK_RPC_REQUEST) break;
+ } while (*buflen);
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_request(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen, mpack_data_t data)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_request_tok(session, &tok, data);
+ }
+ if (status == MPACK_NOMEM) break;
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_reply(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen, mpack_uint32_t id)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_reply_tok(session, &tok, id);
+ }
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API int mpack_rpc_notify(mpack_rpc_session_t *session, char **buf,
+ size_t *buflen)
+{
+ int status = MPACK_EOF;
+
+ while (status && *buflen) {
+ int write_status;
+ mpack_token_t tok;
+ if (!session->writer.plen) {
+ status = mpack_rpc_notify_tok(session, &tok);
+ }
+ write_status = mpack_write(&session->writer, buf, buflen, &tok);
+ status = write_status ? write_status : status;
+ }
+
+ return status;
+}
+
+MPACK_API void mpack_rpc_session_copy(mpack_rpc_session_t *dst,
+ mpack_rpc_session_t *src)
+{
+ mpack_uint32_t i;
+ mpack_uint32_t dst_capacity = dst->capacity;
+ assert(src->capacity <= dst_capacity);
+ /* copy all fields except slots */
+ memcpy(dst, src, sizeof(mpack_rpc_one_session_t) -
+ sizeof(struct mpack_rpc_slot_s));
+ /* reset capacity */
+ dst->capacity = dst_capacity;
+ /* reinsert requests */
+ memset(dst->slots, 0, sizeof(struct mpack_rpc_slot_s) * dst->capacity);
+ for (i = 0; i < src->capacity; i++) {
+ if (src->slots[i].used) mpack_rpc_put(dst, src->slots[i].msg);
+ }
+}
+
+static mpack_rpc_header_t mpack_rpc_request_hdr(void)
+{
+ mpack_rpc_header_t hdr;
+ hdr.index = 0;
+ hdr.toks[0].type = MPACK_TOKEN_ARRAY;
+ hdr.toks[0].length = 4;
+ hdr.toks[1].type = MPACK_TOKEN_UINT;
+ hdr.toks[1].data.value.lo = 0;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static mpack_rpc_header_t mpack_rpc_reply_hdr(void)
+{
+ mpack_rpc_header_t hdr = mpack_rpc_request_hdr();
+ hdr.toks[1].data.value.lo = 1;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static mpack_rpc_header_t mpack_rpc_notify_hdr(void)
+{
+ mpack_rpc_header_t hdr = mpack_rpc_request_hdr();
+ hdr.toks[0].length = 3;
+ hdr.toks[1].data.value.lo = 2;
+ hdr.toks[1].data.value.hi = 0;
+ return hdr;
+}
+
+static int mpack_rpc_put(mpack_rpc_session_t *session, mpack_rpc_message_t msg)
+{
+ struct mpack_rpc_slot_s *slot = NULL;
+ mpack_uint32_t i;
+ mpack_uint32_t hash = msg.id % session->capacity;
+
+ for (i = 0; i < session->capacity; i++) {
+ if (!session->slots[hash].used || session->slots[hash].msg.id == msg.id) {
+ slot = session->slots + hash;
+ break;
+ }
+ hash = hash > 0 ? hash - 1 : session->capacity - 1;
+ }
+
+ if (!slot) return -1; /* no space */
+ if (slot->msg.id == msg.id && slot->used) return 0; /* duplicate key */
+ slot->msg = msg;
+ slot->used = 1;
+ return 1;
+}
+
+static int mpack_rpc_pop(mpack_rpc_session_t *session, mpack_rpc_message_t *msg)
+{
+ struct mpack_rpc_slot_s *slot = NULL;
+ mpack_uint32_t i;
+ mpack_uint32_t hash = msg->id % session->capacity;
+
+ for (i = 0; i < session->capacity; i++) {
+ if (session->slots[hash].used && session->slots[hash].msg.id == msg->id) {
+ slot = session->slots + hash;
+ break;
+ }
+ hash = hash > 0 ? hash - 1 : session->capacity - 1;
+ }
+
+ if (!slot) return 0;
+
+ *msg = slot->msg;
+ slot->used = 0;
+
+ return 1;
+}
+
+static void mpack_rpc_reset_hdr(mpack_rpc_header_t *hdr)
+{
+ hdr->index = 0;
+}