blob: 893851a0dbbb20676899a2a07e16ede6212d45de [file] [log] [blame]
Klement Sekeradc15be22017-06-12 06:49:33 +02001/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2017 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *------------------------------------------------------------------
16 */
17
18#ifndef vapi_hpp_included
19#define vapi_hpp_included
20
21#include <cstddef>
22#include <vector>
23#include <mutex>
24#include <queue>
25#include <cassert>
26#include <functional>
27#include <algorithm>
28#include <atomic>
29#include <vppinfra/types.h>
30#include <vapi/vapi.h>
31#include <vapi/vapi_internal.h>
32#include <vapi/vapi_dbg.h>
33#include <vapi/vpe.api.vapi.h>
34
35#if VAPI_CPP_DEBUG_LEAKS
36#include <unordered_set>
37#endif
38
39/**
40 * @file
41 * @brief C++ VPP API
42 */
43
44namespace vapi
45{
46
47class Connection;
48
49template <typename Req, typename Resp, typename... Args> class Request;
50template <typename M> class Msg;
51template <typename M> void vapi_swap_to_be (M *msg);
52template <typename M> void vapi_swap_to_host (M *msg);
53template <typename M, typename... Args>
54M *vapi_alloc (Connection &con, Args...);
55template <typename M> vapi_msg_id_t vapi_get_msg_id_t ();
56template <typename M> class Event_registration;
57
58class Unexpected_msg_id_exception : public std::exception
59{
60public:
61 virtual const char *what () const throw ()
62 {
63 return "unexpected message id";
64 }
65};
66
67class Msg_not_available_exception : public std::exception
68{
69public:
70 virtual const char *what () const throw ()
71 {
72 return "message unavailable";
73 }
74};
75
76typedef enum {
77 /** response not ready yet */
78 RESPONSE_NOT_READY,
79
80 /** response to request is ready */
81 RESPONSE_READY,
82
83 /** no response to request (will never come) */
84 RESPONSE_NO_RESPONSE,
85} vapi_response_state_e;
86
87/**
88 * Class representing common functionality of a request - response state
89 * and context
90 */
91class Common_req
92{
93public:
94 virtual ~Common_req (){};
95
96 Connection &get_connection ()
97 {
98 return con;
99 };
100
101 vapi_response_state_e get_response_state (void) const
102 {
103 return response_state;
104 }
105
106private:
107 Connection &con;
Neale Rannsfd67ece2017-11-02 11:59:14 -0700108 Common_req (Connection &con)
109 : con (con), context{0}, response_state{RESPONSE_NOT_READY}
Klement Sekeradc15be22017-06-12 06:49:33 +0200110 {
111 }
112
113 void set_response_state (vapi_response_state_e state)
114 {
115 response_state = state;
116 }
117
118 virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
119 void *shm_data) = 0;
120
121 void set_context (u32 context)
122 {
123 this->context = context;
124 }
125
126 u32 get_context ()
127 {
128 return context;
129 }
130
131 u32 context;
132 vapi_response_state_e response_state;
133
134 friend class Connection;
135
136 template <typename M> friend class Msg;
137
138 template <typename Req, typename Resp, typename... Args>
139 friend class Request;
140
141 template <typename Req, typename Resp, typename... Args> friend class Dump;
142
143 template <typename M> friend class Event_registration;
144};
145
146/**
147 * Class representing a connection to VPP
148 *
149 * After creating a Connection object, call connect() to actually connect
150 * to VPP. Use is_msg_available to discover whether a specific message is known
151 * and supported by the VPP connected to.
152 */
153class Connection
154{
155public:
156 Connection (void) : vapi_ctx{0}, event_count{0}
157 {
158
159 vapi_error_e rv = VAPI_OK;
160 if (!vapi_ctx)
161 {
162 if (VAPI_OK != (rv = vapi_ctx_alloc (&vapi_ctx)))
163 {
164 throw std::bad_alloc ();
165 }
166 }
167 events.reserve (vapi_get_message_count () + 1);
168 }
169
170 Connection (const Connection &) = delete;
171
172 ~Connection (void)
173 {
174 vapi_ctx_free (vapi_ctx);
175#if VAPI_CPP_DEBUG_LEAKS
176 for (auto x : shm_data_set)
177 {
178 printf ("Leaked shm_data@%p!\n", x);
179 }
180#endif
181 }
182
183 /**
184 * @brief check if message identified by it's message id is known by the
185 * vpp to which the connection is open
186 */
187 bool is_msg_available (vapi_msg_id_t type)
188 {
189 return vapi_is_msg_available (vapi_ctx, type);
190 }
191
192 /**
193 * @brief connect to vpp
194 *
195 * @param name application name
196 * @param chroot_prefix shared memory prefix
197 * @param max_queued_request max number of outstanding requests queued
198 *
199 * @return VAPI_OK on success, other error code on error
200 */
201 vapi_error_e connect (const char *name, const char *chroot_prefix,
202 int max_outstanding_requests, int response_queue_size)
203 {
204 return vapi_connect (vapi_ctx, name, chroot_prefix,
205 max_outstanding_requests, response_queue_size,
206 VAPI_MODE_BLOCKING);
207 }
208
209 /**
210 * @brief disconnect from vpp
211 *
212 * @return VAPI_OK on success, other error code on error
213 */
214 vapi_error_e disconnect ()
215 {
216 auto x = requests.size ();
217 while (x > 0)
218 {
219 VAPI_DBG ("popping request @%p", requests.front ());
220 requests.pop_front ();
221 --x;
222 }
223 return vapi_disconnect (vapi_ctx);
224 };
225
226 /**
227 * @brief get event file descriptor
228 *
229 * @note this file descriptor becomes readable when messages (from vpp)
230 * are waiting in queue
231 *
232 * @param[out] fd pointer to result variable
233 *
234 * @return VAPI_OK on success, other error code on error
235 */
236 vapi_error_e get_fd (int *fd)
237 {
238 return vapi_get_fd (vapi_ctx, fd);
239 }
240
241 /**
242 * @brief wait for responses from vpp and assign them to appropriate objects
243 *
244 * @param limit stop dispatch after the limit object received it's response
245 *
246 * @return VAPI_OK on success, other error code on error
247 */
248 vapi_error_e dispatch (const Common_req *limit = nullptr)
249 {
250 std::lock_guard<std::mutex> lock (dispatch_mutex);
251 vapi_error_e rv = VAPI_OK;
252 bool loop_again = true;
253 while (loop_again)
254 {
255 void *shm_data;
256 size_t shm_data_size;
257 rv = vapi_recv (vapi_ctx, &shm_data, &shm_data_size);
258 if (VAPI_OK != rv)
259 {
260 return rv;
261 }
262#if VAPI_CPP_DEBUG_LEAKS
263 on_shm_data_alloc (shm_data);
264#endif
265 std::lock_guard<std::recursive_mutex> requests_lock (requests_mutex);
266 std::lock_guard<std::recursive_mutex> events_lock (events_mutex);
267 vapi_msg_id_t id = vapi_lookup_vapi_msg_id_t (
268 vapi_ctx, be16toh (*static_cast<u16 *> (shm_data)));
269 bool has_context = vapi_msg_is_with_context (id);
270 bool break_dispatch = false;
271 Common_req *matching_req = nullptr;
272 if (has_context)
273 {
274 u32 context = *reinterpret_cast<u32 *> (
275 (static_cast<u8 *> (shm_data) + vapi_get_context_offset (id)));
276 const auto x = requests.front ();
277 matching_req = x;
278 if (context == x->context)
279 {
280 std::tie (rv, break_dispatch) =
281 x->assign_response (id, shm_data);
282 }
283 else
284 {
285 std::tie (rv, break_dispatch) =
286 x->assign_response (id, nullptr);
287 }
288 if (break_dispatch)
289 {
290 requests.pop_front ();
291 }
292 }
293 else
294 {
295 if (events[id])
296 {
297 std::tie (rv, break_dispatch) =
298 events[id]->assign_response (id, shm_data);
299 matching_req = events[id];
300 }
301 else
302 {
303 msg_free (shm_data);
304 }
305 }
306 if ((matching_req && matching_req == limit && break_dispatch) ||
307 VAPI_OK != rv)
308 {
309 return rv;
310 }
311 loop_again = !requests.empty () || (event_count > 0);
312 }
313 return rv;
314 }
315
316 /**
317 * @brief convenience wrapper function
318 */
319 vapi_error_e dispatch (const Common_req &limit)
320 {
321 return dispatch (&limit);
322 }
323
324 /**
325 * @brief wait for response to a specific request
326 *
327 * @param req request to wait for response for
328 *
329 * @return VAPI_OK on success, other error code on error
330 */
331 vapi_error_e wait_for_response (const Common_req &req)
332 {
333 if (RESPONSE_READY == req.get_response_state ())
334 {
335 return VAPI_OK;
336 }
337 return dispatch (req);
338 }
339
340private:
341 void msg_free (void *shm_data)
342 {
343#if VAPI_CPP_DEBUG_LEAKS
344 on_shm_data_free (shm_data);
345#endif
346 vapi_msg_free (vapi_ctx, shm_data);
347 }
348
349 template <template <typename XReq, typename XResp, typename... XArgs>
350 class X,
351 typename Req, typename Resp, typename... Args>
352 vapi_error_e send (X<Req, Resp, Args...> *req)
353 {
354 if (!req)
355 {
356 return VAPI_EINVAL;
357 }
358 u32 req_context =
359 req_context_counter.fetch_add (1, std::memory_order_relaxed);
360 req->request.shm_data->header.context = req_context;
361 vapi_swap_to_be<Req> (req->request.shm_data);
362 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
363 vapi_error_e rv = vapi_send (vapi_ctx, req->request.shm_data);
364 if (VAPI_OK == rv)
365 {
366 VAPI_DBG ("Push %p", req);
367 requests.emplace_back (req);
368 req->set_context (req_context);
369#if VAPI_CPP_DEBUG_LEAKS
370 on_shm_data_free (req->request.shm_data);
371#endif
372 req->request.shm_data = nullptr; /* consumed by vapi_send */
373 }
374 else
375 {
376 vapi_swap_to_host<Req> (req->request.shm_data);
377 }
378 return rv;
379 }
380
381 template <template <typename XReq, typename XResp, typename... XArgs>
382 class X,
383 typename Req, typename Resp, typename... Args>
384 vapi_error_e send_with_control_ping (X<Req, Resp, Args...> *req)
385 {
386 if (!req)
387 {
388 return VAPI_EINVAL;
389 }
390 u32 req_context =
391 req_context_counter.fetch_add (1, std::memory_order_relaxed);
392 req->request.shm_data->header.context = req_context;
393 vapi_swap_to_be<Req> (req->request.shm_data);
394 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
395 vapi_error_e rv = vapi_send_with_control_ping (
396 vapi_ctx, req->request.shm_data, req_context);
397 if (VAPI_OK == rv)
398 {
399 VAPI_DBG ("Push %p", req);
400 requests.emplace_back (req);
401 req->set_context (req_context);
402#if VAPI_CPP_DEBUG_LEAKS
403 on_shm_data_free (req->request.shm_data);
404#endif
405 req->request.shm_data = nullptr; /* consumed by vapi_send */
406 }
407 else
408 {
409 vapi_swap_to_host<Req> (req->request.shm_data);
410 }
411 return rv;
412 }
413
414 void unregister_request (Common_req *request)
415 {
416 std::lock_guard<std::recursive_mutex> lock (requests_mutex);
417 std::remove (requests.begin (), requests.end (), request);
418 }
419
420 template <typename M> void register_event (Event_registration<M> *event)
421 {
422 const vapi_msg_id_t id = M::get_msg_id ();
423 std::lock_guard<std::recursive_mutex> lock (events_mutex);
424 events[id] = event;
425 ++event_count;
426 }
427
428 template <typename M> void unregister_event (Event_registration<M> *event)
429 {
430 const vapi_msg_id_t id = M::get_msg_id ();
431 std::lock_guard<std::recursive_mutex> lock (events_mutex);
432 events[id] = nullptr;
433 --event_count;
434 }
435
436 vapi_ctx_t vapi_ctx;
437 std::atomic_ulong req_context_counter;
438 std::mutex dispatch_mutex;
439
440 std::recursive_mutex requests_mutex;
441 std::recursive_mutex events_mutex;
442 std::deque<Common_req *> requests;
443 std::vector<Common_req *> events;
444 int event_count;
445
446 template <typename Req, typename Resp, typename... Args>
447 friend class Request;
448
449 template <typename Req, typename Resp, typename... Args> friend class Dump;
450
451 template <typename M> friend class Result_set;
452
453 template <typename M> friend class Event_registration;
454
455 template <typename M, typename... Args>
456 friend M *vapi_alloc (Connection &con, Args...);
457
458 template <typename M> friend class Msg;
459
460#if VAPI_CPP_DEBUG_LEAKS
461 void on_shm_data_alloc (void *shm_data)
462 {
463 if (shm_data)
464 {
465 auto pos = shm_data_set.find (shm_data);
466 if (pos == shm_data_set.end ())
467 {
468 shm_data_set.insert (shm_data);
469 }
470 else
471 {
472 printf ("Double-add shm_data @%p!\n", shm_data);
473 }
474 }
475 }
476
477 void on_shm_data_free (void *shm_data)
478 {
479 auto pos = shm_data_set.find (shm_data);
480 if (pos == shm_data_set.end ())
481 {
482 printf ("Freeing untracked shm_data @%p!\n", shm_data);
483 }
484 else
485 {
486 shm_data_set.erase (pos);
487 }
488 }
489 std::unordered_set<void *> shm_data_set;
490#endif
491};
492
493template <typename Req, typename Resp, typename... Args> class Request;
494
495template <typename Req, typename Resp, typename... Args> class Dump;
496
497template <class, class = void> struct vapi_has_payload_trait : std::false_type
498{
499};
500
501template <class... T> using vapi_void_t = void;
502
503template <class T>
504struct vapi_has_payload_trait<T, vapi_void_t<decltype (&T::payload)>>
505 : std::true_type
506{
507};
508
509template <typename M> void vapi_msg_set_msg_id (vapi_msg_id_t id)
510{
511 Msg<M>::set_msg_id (id);
512}
513
514/**
515 * Class representing a message stored in shared memory
516 */
517template <typename M> class Msg
518{
519public:
520 Msg (const Msg &) = delete;
521
522 ~Msg ()
523 {
524 VAPI_DBG ("Destroy Msg<%s>@%p, shm_data@%p",
525 vapi_get_msg_name (get_msg_id ()), this, shm_data);
526 if (shm_data)
527 {
528 con.get ().msg_free (shm_data);
529 shm_data = nullptr;
530 }
531 }
532
533 static vapi_msg_id_t get_msg_id ()
534 {
535 return *msg_id_holder ();
536 }
537
538 template <typename X = M>
539 typename std::enable_if<vapi_has_payload_trait<X>::value,
540 decltype (X::payload) &>::type
541 get_payload () const
542 {
543 return shm_data->payload;
544 }
545
546private:
547 Msg (Msg<M> &&msg) : con{msg.con}
548 {
549 VAPI_DBG ("Move construct Msg<%s> from msg@%p to msg@%p, shm_data@%p",
550 vapi_get_msg_name (get_msg_id ()), &msg, this, msg.shm_data);
551 shm_data = msg.shm_data;
552 msg.shm_data = nullptr;
553 }
554
555 Msg<M> &operator= (Msg<M> &&msg)
556 {
557 VAPI_DBG ("Move assign Msg<%s> from msg@%p to msg@%p, shm_data@%p",
558 vapi_get_msg_name (get_msg_id ()), &msg, this, msg.shm_data);
559 con.get ().msg_free (shm_data);
560 con = msg.con;
561 shm_data = msg.shm_data;
562 msg.shm_data = nullptr;
563 return *this;
564 }
565
566 struct Msg_allocator : std::allocator<Msg<M>>
567 {
568 template <class U, class... Args> void construct (U *p, Args &&... args)
569 {
570 ::new ((void *)p) U (std::forward<Args> (args)...);
571 }
572
573 template <class U> struct rebind
574 {
575 typedef Msg_allocator other;
576 };
577 };
578
579 static void set_msg_id (vapi_msg_id_t id)
580 {
Neale Rannsfd67ece2017-11-02 11:59:14 -0700581 assert ((INVALID_MSG_ID == *msg_id_holder ()) ||
582 (id == *msg_id_holder ()));
Klement Sekeradc15be22017-06-12 06:49:33 +0200583 *msg_id_holder () = id;
584 }
585
586 static vapi_msg_id_t *msg_id_holder ()
587 {
Neale Rannsfd67ece2017-11-02 11:59:14 -0700588 static vapi_msg_id_t my_id{INVALID_MSG_ID};
Klement Sekeradc15be22017-06-12 06:49:33 +0200589 return &my_id;
590 }
591
Klement Sekera905e2502017-09-22 07:52:28 +0200592 Msg (Connection &con, void *shm_data) : con{con}
Klement Sekeradc15be22017-06-12 06:49:33 +0200593 {
594 if (!con.is_msg_available (get_msg_id ()))
595 {
596 throw Msg_not_available_exception ();
597 }
598 this->shm_data = static_cast<shm_data_type *> (shm_data);
599 VAPI_DBG ("New Msg<%s>@%p shm_data@%p", vapi_get_msg_name (get_msg_id ()),
600 this, shm_data);
601 }
602
Klement Sekera905e2502017-09-22 07:52:28 +0200603 void assign_response (vapi_msg_id_t resp_id, void *shm_data)
Klement Sekeradc15be22017-06-12 06:49:33 +0200604 {
605 assert (nullptr == this->shm_data);
606 if (resp_id != get_msg_id ())
607 {
608 throw Unexpected_msg_id_exception ();
609 }
610 this->shm_data = static_cast<M *> (shm_data);
611 vapi_swap_to_host<M> (this->shm_data);
612 VAPI_DBG ("Assign response to Msg<%s>@%p shm_data@%p",
613 vapi_get_msg_name (get_msg_id ()), this, shm_data);
614 }
615
616 std::reference_wrapper<Connection> con;
617 using shm_data_type = M;
618 shm_data_type *shm_data;
619
620 friend class Connection;
621
622 template <typename Req, typename Resp, typename... Args>
623 friend class Request;
624
625 template <typename Req, typename Resp, typename... Args> friend class Dump;
626
627 template <typename X> friend class Event_registration;
628
629 template <typename X> friend class Result_set;
630
631 friend struct Msg_allocator;
632
633 template <typename X> friend void vapi_msg_set_msg_id (vapi_msg_id_t id);
634};
635
636/**
637 * Class representing a simple request - with a single response message
638 */
639template <typename Req, typename Resp, typename... Args>
640class Request : public Common_req
641{
642public:
643 Request (Connection &con, Args... args,
644 std::function<vapi_error_e (Request<Req, Resp, Args...> &)>
645 callback = nullptr)
646 : Common_req{con}, callback{callback},
647 request{con, vapi_alloc<Req> (con, args...)}, response{con, nullptr}
648 {
649 }
650
651 Request (const Request &) = delete;
652
653 virtual ~Request ()
654 {
655 if (RESPONSE_NOT_READY == get_response_state ())
656 {
657 con.unregister_request (this);
658 }
659 }
660
661 vapi_error_e execute ()
662 {
663 return con.send (this);
664 }
665
666 const Msg<Req> &get_request (void) const
667 {
668 return request;
669 }
670
671 const Msg<Resp> &get_response (void)
672 {
673 return response;
674 }
675
676private:
677 virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
678 void *shm_data)
679 {
680 assert (RESPONSE_NOT_READY == get_response_state ());
681 response.assign_response (id, shm_data);
682 set_response_state (RESPONSE_READY);
683 if (nullptr != callback)
684 {
685 return std::make_pair (callback (*this), true);
686 }
687 return std::make_pair (VAPI_OK, true);
688 }
689 std::function<vapi_error_e (Request<Req, Resp, Args...> &)> callback;
690 Msg<Req> request;
691 Msg<Resp> response;
692
693 friend class Connection;
694};
695
696/**
697 * Class representing iterable set of responses of the same type
698 */
699template <typename M> class Result_set
700{
701public:
702 ~Result_set ()
703 {
704 }
705
706 Result_set (const Result_set &) = delete;
707
708 bool is_complete () const
709 {
710 return complete;
711 }
712
713 size_t size () const
714 {
715 return set.size ();
716 }
717
718 using const_iterator =
719 typename std::vector<Msg<M>,
720 typename Msg<M>::Msg_allocator>::const_iterator;
721
722 const_iterator begin () const
723 {
724 return set.begin ();
725 }
726
727 const_iterator end () const
728 {
729 return set.end ();
730 }
731
732 void free_response (const_iterator pos)
733 {
734 set.erase (pos);
735 }
736
737 void free_all_responses ()
738 {
739 set.clear ();
740 }
741
742private:
743 void mark_complete ()
744 {
745 complete = true;
746 }
747
Klement Sekera905e2502017-09-22 07:52:28 +0200748 void assign_response (vapi_msg_id_t resp_id, void *shm_data)
Klement Sekeradc15be22017-06-12 06:49:33 +0200749 {
750 if (resp_id != Msg<M>::get_msg_id ())
751 {
752 {
753 throw Unexpected_msg_id_exception ();
754 }
755 }
756 else if (shm_data)
757 {
758 vapi_swap_to_host<M> (static_cast<M *> (shm_data));
759 set.emplace_back (con, shm_data);
760 VAPI_DBG ("Result_set@%p emplace_back shm_data@%p", this, shm_data);
761 }
762 }
763
Neale Ranns812ed392017-10-16 04:20:13 -0700764 Result_set (Connection &con) : con (con), complete{false}
Klement Sekeradc15be22017-06-12 06:49:33 +0200765 {
766 }
767
768 Connection &con;
769 bool complete;
770 std::vector<Msg<M>, typename Msg<M>::Msg_allocator> set;
771
772 template <typename Req, typename Resp, typename... Args> friend class Dump;
773
774 template <typename X> friend class Event_registration;
775};
776
777/**
778 * Class representing a dump request - zero or more identical responses to a
779 * single request message
780 */
781template <typename Req, typename Resp, typename... Args>
782class Dump : public Common_req
783{
784public:
785 Dump (Connection &con, Args... args,
786 std::function<vapi_error_e (Dump<Req, Resp, Args...> &)> callback =
787 nullptr)
788 : Common_req{con}, request{con, vapi_alloc<Req> (con, args...)},
789 result_set{con}, callback{callback}
790 {
791 }
792
793 Dump (const Dump &) = delete;
794
795 virtual ~Dump ()
796 {
797 }
798
799 virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
800 void *shm_data)
801 {
802 if (id == vapi_msg_id_control_ping_reply)
803 {
804 con.msg_free (shm_data);
805 result_set.mark_complete ();
806 set_response_state (RESPONSE_READY);
807 if (nullptr != callback)
808 {
809 return std::make_pair (callback (*this), true);
810 }
811 return std::make_pair (VAPI_OK, true);
812 }
813 else
814 {
815 result_set.assign_response (id, shm_data);
816 }
817 return std::make_pair (VAPI_OK, false);
818 }
819
820 vapi_error_e execute ()
821 {
822 return con.send_with_control_ping (this);
823 }
824
825 Msg<Req> &get_request (void)
826 {
827 return request;
828 }
829
830 using resp_type = typename Msg<Resp>::shm_data_type;
831
832 const Result_set<Resp> &get_result_set (void) const
833 {
834 return result_set;
835 }
836
837private:
838 Msg<Req> request;
839 Result_set<resp_type> result_set;
840 std::function<vapi_error_e (Dump<Req, Resp, Args...> &)> callback;
841
842 friend class Connection;
843};
844
845/**
846 * Class representing event registration - incoming events (messages) from
847 * vpp as a result of a subscription (typically a want_* simple request)
848 */
849template <typename M> class Event_registration : public Common_req
850{
851public:
852 Event_registration (
853 Connection &con,
Klement Sekera905e2502017-09-22 07:52:28 +0200854 std::function<vapi_error_e (Event_registration<M> &)> callback = nullptr)
Klement Sekeradc15be22017-06-12 06:49:33 +0200855 : Common_req{con}, result_set{con}, callback{callback}
856 {
857 if (!con.is_msg_available (M::get_msg_id ()))
858 {
859 throw Msg_not_available_exception ();
860 }
861 con.register_event (this);
862 }
863
864 Event_registration (const Event_registration &) = delete;
865
866 virtual ~Event_registration ()
867 {
868 con.unregister_event (this);
869 }
870
871 virtual std::tuple<vapi_error_e, bool> assign_response (vapi_msg_id_t id,
872 void *shm_data)
873 {
874 result_set.assign_response (id, shm_data);
875 if (nullptr != callback)
876 {
877 return std::make_pair (callback (*this), true);
878 }
879 return std::make_pair (VAPI_OK, true);
880 }
881
882 using resp_type = typename M::shm_data_type;
883
884 Result_set<resp_type> &get_result_set (void)
885 {
886 return result_set;
887 }
888
889private:
890 Result_set<resp_type> result_set;
891 std::function<vapi_error_e (Event_registration<M> &)> callback;
892};
893};
894
895#endif
896
897/*
898 * fd.io coding-style-patch-verification: ON
899 *
900 * Local Variables:
901 * eval: (c-set-style "gnu")
902 * End:
903 */