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 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
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 
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 };
52 struct frrzmq_cb {
53 	void *zmqsock;
54 	int fd;
55 
56 	struct cb_core read;
57 	struct cb_core write;
58 };
59 
60 /* libzmq's context
61  *
62  * this is mostly here as a convenience, it has IPv6 enabled but nothing
63  * else is tied to it;  you can use a separate context without problems
64  */
65 extern void *frrzmq_context;
66 
67 extern void frrzmq_init(void);
68 extern void frrzmq_finish(void);
69 
70 #define debugargdef const char *funcname, const char *schedfrom, int fromln
71 
72 /* core event registration, one of these 2 macros should be used */
73 #define frrzmq_thread_add_read_msg(m, f, e, a, z, d)                           \
74 	funcname_frrzmq_thread_add_read(m, f, NULL, e, a, z, d, #f, __FILE__,  \
75 					__LINE__)
76 #define frrzmq_thread_add_read_part(m, f, e, a, z, d)                          \
77 	funcname_frrzmq_thread_add_read(m, NULL, f, e, a, z, d, #f, __FILE__,  \
78 					__LINE__)
79 #define frrzmq_thread_add_write_msg(m, f, e, a, z, d)                          \
80 	funcname_frrzmq_thread_add_write(m, f, e, a, z, d, #f, __FILE__,       \
81 					 __LINE__)
82 
83 struct cb_core;
84 struct frrzmq_cb;
85 
86 /* Set up a POLLIN or POLLOUT notification to be called from the libfrr main
87  * loop. This has the following properties:
88  *
89  * - since ZeroMQ works with edge triggered notifications, it will loop and
90  *   dispatch as many events as ZeroMQ has pending at the time libfrr calls
91  *   into this code
92  * - due to this looping (which means it non-single-issue), the callback is
93  *   also persistent.  Do _NOT_ re-register the event inside of your
94  *   callback function.
95  * - either msgfunc or partfunc will be called (only one can be specified)
96  *   - msgfunc is called once for each incoming message
97  *   - if partfunc is specified, the message is read and partfunc is called
98  *     for each ZeroMQ multi-part subpart.  Note that you can't send replies
99  *     before all parts have been read because that violates the ZeroMQ FSM.
100  * - write version doesn't allow for partial callback, you must handle the
101  *   whole message (all parts) in msgfunc callback
102  * - you can safely cancel the callback from within itself
103  * - installing a callback will check for pending events (ZMQ_EVENTS) and
104  *   may schedule the event to run as soon as libfrr is back in its main
105  *   loop.
106  */
107 extern int funcname_frrzmq_thread_add_read(
108 	struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
109 	void (*partfunc)(void *arg, void *zmqsock, zmq_msg_t *msg,
110 			 unsigned partnum),
111 	void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
112 	struct frrzmq_cb **cb, debugargdef);
113 extern int funcname_frrzmq_thread_add_write(
114 	struct thread_master *master, void (*msgfunc)(void *arg, void *zmqsock),
115 	void (*errfunc)(void *arg, void *zmqsock), void *arg, void *zmqsock,
116 	struct frrzmq_cb **cb, debugargdef);
117 
118 extern void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core);
119 
120 /*
121  * http://api.zeromq.org/4-2:zmq-getsockopt#toc10
122  *
123  * As the descriptor is edge triggered, applications must update the state of
124  * ZMQ_EVENTS after each invocation of zmq_send or zmq_recv.To be more explicit:
125  * after calling zmq_send the socket may become readable (and vice versa)
126  * without triggering a read event on the file descriptor.
127  */
128 extern void frrzmq_check_events(struct frrzmq_cb **cbp, struct cb_core *core,
129 				int event);
130 
131 #ifdef __cplusplus
132 }
133 #endif
134 
135 #endif /* _FRRZMQ_H */
136