]>
Commit | Line | Data |
---|---|---|
b6116506 DL |
1 | /* |
2 | * libzebra ZeroMQ bindings | |
3 | * Copyright (C) 2015 David Lamparter | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the Free | |
7 | * Software Foundation; either version 2 of the License, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along | |
16 | * with this program; see the file COPYING; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | */ | |
19 | ||
20 | #ifndef _FRRZMQ_H | |
21 | #define _FRRZMQ_H | |
22 | ||
23 | #include "thread.h" | |
24 | #include <zmq.h> | |
25 | ||
5e244469 RW |
26 | #ifdef __cplusplus |
27 | extern "C" { | |
28 | #endif | |
29 | ||
f3cd305f DL |
30 | /* linking/packaging note: this is a separate library that needs to be |
31 | * linked into any daemon/library/module that wishes to use its | |
32 | * functionality. The purpose of this is to encapsulate the libzmq | |
33 | * dependency and not make libfrr/FRR itself depend on libzmq. | |
34 | * | |
35 | * libfrrzmq should be put in LDFLAGS/LIBADD *before* either libfrr or | |
36 | * libzmq, and both of these should always be listed, e.g. | |
37 | * foo_LDFLAGS = libfrrzmq.la libfrr.la $(ZEROMQ_LIBS) | |
38 | */ | |
39 | ||
afd0f10d | 40 | /* callback integration */ |
41 | struct cb_core { | |
42 | struct thread *thread; | |
43 | void *arg; | |
44 | ||
45 | bool cancelled; | |
46 | ||
47 | void (*cb_msg)(void *arg, void *zmqsock); | |
48 | void (*cb_part)(void *arg, void *zmqsock, zmq_msg_t *msg, | |
49 | unsigned partnum); | |
50 | void (*cb_error)(void *arg, void *zmqsock); | |
51 | }; | |
8fd5502b | 52 | |
afd0f10d | 53 | struct frrzmq_cb { |
54 | void *zmqsock; | |
55 | int fd; | |
56 | ||
8fd5502b MS |
57 | bool in_cb; /* This context is in a read or write callback. */ |
58 | ||
afd0f10d | 59 | struct cb_core read; |
60 | struct cb_core write; | |
61 | }; | |
62 | ||
f3cd305f DL |
63 | /* libzmq's context |
64 | * | |
65 | * this is mostly here as a convenience, it has IPv6 enabled but nothing | |
66 | * else is tied to it; you can use a separate context without problems | |
67 | */ | |
b6116506 DL |
68 | extern void *frrzmq_context; |
69 | ||
afd0f10d | 70 | extern void frrzmq_init(void); |
71 | extern void frrzmq_finish(void); | |
b6116506 | 72 | |
60a3efec DL |
73 | #define _xref_zmq_a(type, f, d, call) \ |
74 | ({ \ | |
75 | static const struct xref_threadsched _xref \ | |
76 | __attribute__((used)) = { \ | |
77 | .xref = XREF_INIT(XREFT_THREADSCHED, NULL, __func__), \ | |
78 | .funcname = #f, \ | |
79 | .dest = #d, \ | |
80 | .thread_type = THREAD_ ## type, \ | |
81 | }; \ | |
82 | XREF_LINK(_xref.xref); \ | |
83 | call; \ | |
84 | }) \ | |
85 | /* end */ | |
b6116506 | 86 | |
f3cd305f | 87 | /* core event registration, one of these 2 macros should be used */ |
afd0f10d | 88 | #define frrzmq_thread_add_read_msg(m, f, e, a, z, d) \ |
60a3efec DL |
89 | _xref_zmq_a(READ, f, d, \ |
90 | _frrzmq_thread_add_read(&_xref, m, f, NULL, e, a, z, d)) | |
91 | ||
afd0f10d | 92 | #define frrzmq_thread_add_read_part(m, f, e, a, z, d) \ |
60a3efec DL |
93 | _xref_zmq_a(READ, f, d, \ |
94 | _frrzmq_thread_add_read(&_xref, m, NULL, f, e, a, z, d)) | |
95 | ||
afd0f10d | 96 | #define frrzmq_thread_add_write_msg(m, f, e, a, z, d) \ |
60a3efec DL |
97 | _xref_zmq_a(WRITE, f, d, \ |
98 | _frrzmq_thread_add_write(&_xref, m, f, e, a, z, d)) | |
b6116506 | 99 | |
afd0f10d | 100 | struct cb_core; |
b6116506 DL |
101 | struct frrzmq_cb; |
102 | ||
afd0f10d | 103 | /* Set up a POLLIN or POLLOUT notification to be called from the libfrr main |
104 | * loop. This has the following properties: | |
f3cd305f DL |
105 | * |
106 | * - since ZeroMQ works with edge triggered notifications, it will loop and | |
107 | * dispatch as many events as ZeroMQ has pending at the time libfrr calls | |
108 | * into this code | |
109 | * - due to this looping (which means it non-single-issue), the callback is | |
110 | * also persistent. Do _NOT_ re-register the event inside of your | |
111 | * callback function. | |
112 | * - either msgfunc or partfunc will be called (only one can be specified) | |
113 | * - msgfunc is called once for each incoming message | |
114 | * - if partfunc is specified, the message is read and partfunc is called | |
115 | * for each ZeroMQ multi-part subpart. Note that you can't send replies | |
116 | * before all parts have been read because that violates the ZeroMQ FSM. | |
afd0f10d | 117 | * - write version doesn't allow for partial callback, you must handle the |
118 | * whole message (all parts) in msgfunc callback | |
f3cd305f DL |
119 | * - you can safely cancel the callback from within itself |
120 | * - installing a callback will check for pending events (ZMQ_EVENTS) and | |
121 | * may schedule the event to run as soon as libfrr is back in its main | |
122 | * loop. | |
afd0f10d | 123 | */ |
60a3efec DL |
124 | extern int _frrzmq_thread_add_read( |
125 | const struct xref_threadsched *xref, struct thread_master *master, | |
126 | void (*msgfunc)(void *arg, void *zmqsock), | |
afd0f10d | 127 | void (*partfunc)(void *arg, void *zmqsock, zmq_msg_t *msg, |
128 | unsigned partnum), | |
129 | void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock, | |
60a3efec DL |
130 | struct frrzmq_cb **cb); |
131 | extern int _frrzmq_thread_add_write( | |
132 | const struct xref_threadsched *xref, struct thread_master *master, | |
133 | void (*msgfunc)(void *arg, void *zmqsock), | |
afd0f10d | 134 | void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock, |
60a3efec | 135 | struct frrzmq_cb **cb); |
afd0f10d | 136 | |
137 | extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core); | |
138 | ||
139 | /* | |
140 | * http://api.zeromq.org/4-2:zmq-getsockopt#toc10 | |
f3cd305f | 141 | * |
afd0f10d | 142 | * As the descriptor is edge triggered, applications must update the state of |
143 | * ZMQ_EVENTS after each invocation of zmq_send or zmq_recv.To be more explicit: | |
144 | * after calling zmq_send the socket may become readable (and vice versa) | |
145 | * without triggering a read event on the file descriptor. | |
f3cd305f | 146 | */ |
afd0f10d | 147 | extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core, |
148 | int event); | |
b6116506 | 149 | |
5e244469 RW |
150 | #ifdef __cplusplus |
151 | } | |
152 | #endif | |
153 | ||
b6116506 | 154 | #endif /* _FRRZMQ_H */ |