+/* Cut and paste to avoid adding dependency to client library */
+__clib_nosanitize_addr static void
+VL_API_VEC_UNPOISON (const void *v)
+{
+ const vec_header_t *vh = &((vec_header_t *) v)[-1];
+ clib_mem_unpoison (vh, sizeof (*vh) + vec_len (v));
+}
+
+static void
+vapi_api_name_and_crc_free (vapi_ctx_t ctx)
+{
+ int i;
+ u8 **keys = 0;
+ hash_pair_t *hp;
+
+ if (!ctx->msg_index_by_name_and_crc)
+ return;
+ hash_foreach_pair (hp, ctx->msg_index_by_name_and_crc,
+ ({ vec_add1 (keys, (u8 *) hp->key); }));
+ for (i = 0; i < vec_len (keys); i++)
+ vec_free (keys[i]);
+ vec_free (keys);
+ hash_free (ctx->msg_index_by_name_and_crc);
+}
+
+static void
+vapi_memclnt_create_v2_reply_t_handler (vapi_ctx_t ctx,
+ vl_api_memclnt_create_v2_reply_t *mp)
+{
+ serialize_main_t _sm, *sm = &_sm;
+ u8 *tblv;
+ u32 nmsgs;
+ int i;
+ u8 *name_and_crc;
+ u32 msg_index;
+
+ ctx->my_client_index = mp->index;
+
+ /* Clean out any previous hash table (unlikely) */
+ vapi_api_name_and_crc_free (ctx);
+
+ ctx->msg_index_by_name_and_crc = hash_create_string (0, sizeof (uword));
+
+ /* Recreate the vnet-side API message handler table */
+ tblv = uword_to_pointer (mp->message_table, u8 *);
+ unserialize_open_data (sm, tblv, vec_len (tblv));
+ unserialize_integer (sm, &nmsgs, sizeof (u32));
+
+ VL_API_VEC_UNPOISON (tblv);
+
+ for (i = 0; i < nmsgs; i++)
+ {
+ msg_index = unserialize_likely_small_unsigned_integer (sm);
+ unserialize_cstring (sm, (char **) &name_and_crc);
+ hash_set_mem (ctx->msg_index_by_name_and_crc, name_and_crc, msg_index);
+ }
+}
+
+static void
+vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
+ vl_api_memclnt_delete_reply_t *mp)
+{
+ void *oldheap;
+ oldheap = vl_msg_push_heap ();
+ svm_queue_free (ctx->vl_input_queue);
+ vl_msg_pop_heap (oldheap);
+
+ ctx->my_client_index = ~0;
+ ctx->vl_input_queue = 0;
+}
+
+int
+vapi_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
+ int input_queue_size, bool keepalive)
+{
+ vl_api_memclnt_create_v2_t *mp;
+ vl_api_memclnt_create_v2_reply_t *rp;
+ svm_queue_t *vl_input_queue;
+ vl_shmem_hdr_t *shmem_hdr;
+ int rv = 0;
+ void *oldheap;
+ api_main_t *am = vlibapi_get_main ();
+
+ shmem_hdr = am->shmem_hdr;
+
+ if (shmem_hdr == 0 || shmem_hdr->vl_input_queue == 0)
+ {
+ clib_warning ("shmem_hdr / input queue NULL");
+ return -1;
+ }
+
+ clib_mem_unpoison (shmem_hdr, sizeof (*shmem_hdr));
+ VL_MSG_API_SVM_QUEUE_UNPOISON (shmem_hdr->vl_input_queue);
+
+ oldheap = vl_msg_push_heap ();
+ vl_input_queue =
+ svm_queue_alloc_and_init (input_queue_size, sizeof (uword), getpid ());
+ vl_msg_pop_heap (oldheap);
+
+ ctx->my_client_index = ~0;
+ ctx->vl_input_queue = vl_input_queue;
+
+ mp = vl_msg_api_alloc_as_if_client (sizeof (vl_api_memclnt_create_v2_t));
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_CREATE_V2);
+ mp->ctx_quota = ctx_quota;
+ mp->input_queue = (uword) vl_input_queue;
+ strncpy ((char *) mp->name, name, sizeof (mp->name) - 1);
+ mp->keepalive = keepalive;
+
+ vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
+
+ while (1)
+ {
+ int qstatus;
+ struct timespec ts, tsrem;
+ int i;
+
+ /* Wait up to 10 seconds */
+ for (i = 0; i < 1000; i++)
+ {
+ qstatus =
+ svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0);
+ if (qstatus == 0)
+ goto read_one_msg;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 10000 * 1000; /* 10 ms */
+ while (nanosleep (&ts, &tsrem) < 0)
+ ts = tsrem;
+ }
+ /* Timeout... */
+ return -1;
+
+ read_one_msg:
+ VL_MSG_API_UNPOISON (rp);
+ if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_CREATE_V2_REPLY)
+ {
+ clib_warning ("unexpected reply: id %d", ntohs (rp->_vl_msg_id));
+ continue;
+ }
+ rv = clib_net_to_host_u32 (rp->response);
+ vapi_memclnt_create_v2_reply_t_handler (ctx, rp);
+ break;
+ }
+ return (rv);
+}
+
+u32
+vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
+{
+ uword *p;
+
+ if (ctx->msg_index_by_name_and_crc)
+ {
+ p = hash_get_mem (ctx->msg_index_by_name_and_crc, name_and_crc);
+ if (p)
+ return p[0];
+ }
+ return ~0;
+}
+