Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : #include "zeromqrecv.h"
10 :
11 : #include <kdbhelper.h>
12 : #include <kdblogger.h>
13 :
14 : /**
15 : * @internal
16 : * Called whenever the socket becomes readable.
17 : * ZeroMq since sends multipart messages atomically (all or nothing)
18 : * both message parts are instantly available.
19 : *
20 : * @param socket ZeroMq socket
21 : * @param context context passed to elektraIoAdapterZeroMqAttach()
22 : */
23 2 : static void zeroMqRecvSocketReadable (void * socket, void * context)
24 : {
25 2 : ElektraZeroMqRecvPluginData * data = context;
26 :
27 : char * changeType;
28 : char * changedKeyName;
29 :
30 : zmq_msg_t message;
31 2 : zmq_msg_init (&message);
32 :
33 2 : int result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT);
34 2 : if (result == -1)
35 : {
36 : ELEKTRA_LOG_WARNING ("receiving change type failed: %s; aborting", zmq_strerror (zmq_errno ()));
37 0 : zmq_msg_close (&message);
38 0 : return;
39 : }
40 2 : if (!zmq_msg_more (&message))
41 : {
42 : ELEKTRA_LOG_WARNING ("message has only one part; aborting");
43 0 : zmq_msg_close (&message);
44 0 : return;
45 : }
46 2 : int length = zmq_msg_size (&message);
47 2 : changeType = elektraStrNDup (zmq_msg_data (&message), length + 1);
48 2 : changeType[length] = '\0';
49 : ELEKTRA_LOG_DEBUG ("received change type %s", changeType);
50 :
51 2 : result = zmq_msg_recv (&message, socket, ZMQ_DONTWAIT);
52 2 : if (result == -1)
53 : {
54 : ELEKTRA_LOG_WARNING ("receiving key name failed: %s; aborting", zmq_strerror (zmq_errno ()));
55 0 : elektraFree (changeType);
56 0 : zmq_msg_close (&message);
57 0 : return;
58 : }
59 2 : length = zmq_msg_size (&message);
60 2 : changedKeyName = elektraStrNDup (zmq_msg_data (&message), length + 1);
61 2 : changedKeyName[length] = '\0';
62 : ELEKTRA_LOG_DEBUG ("received key name %s", changedKeyName);
63 :
64 : // notify about changes
65 2 : Key * changedKey = keyNew (changedKeyName, KEY_END);
66 2 : data->notificationCallback (changedKey, data->notificationContext);
67 :
68 2 : zmq_msg_close (&message);
69 2 : elektraFree (changeType);
70 2 : elektraFree (changedKeyName);
71 : }
72 :
73 : /**
74 : * @internal
75 : * Setup ZeroMq for receiving notifications.
76 : *
77 : * @param data plugin data containing context, socket, etc.
78 : */
79 4 : void elektraZeroMqRecvSetup (ElektraZeroMqRecvPluginData * data)
80 : {
81 : // create zmq context
82 4 : if (!data->zmqContext)
83 : {
84 4 : data->zmqContext = zmq_ctx_new ();
85 4 : if (data->zmqContext == NULL)
86 : {
87 : ELEKTRA_LOG_WARNING ("zmq_ctx_new failed %s", zmq_strerror (zmq_errno ()));
88 : return;
89 : }
90 : }
91 :
92 : // create publish socket
93 4 : if (!data->zmqSubscriber)
94 : {
95 4 : data->zmqSubscriber = zmq_socket (data->zmqContext, ZMQ_SUB);
96 4 : if (data->zmqSubscriber == NULL)
97 : {
98 : ELEKTRA_LOG_WARNING ("zmq_socket failed %s", zmq_strerror (zmq_errno ()));
99 0 : zmq_close (data->zmqSubscriber);
100 0 : return;
101 : }
102 :
103 : // subscribe to notifications
104 4 : char * keyCommitType = "Commit";
105 4 : if (zmq_setsockopt (data->zmqSubscriber, ZMQ_SUBSCRIBE, keyCommitType, elektraStrLen (keyCommitType)) != 0)
106 : {
107 : ELEKTRA_LOG_WARNING ("failed to subscribe to %s messages", keyCommitType);
108 : }
109 :
110 : // connect to endpoint
111 4 : int result = zmq_connect (data->zmqSubscriber, data->endpoint);
112 4 : if (result != 0)
113 : {
114 : ELEKTRA_LOG_WARNING ("zmq_connect error: %s\n", zmq_strerror (zmq_errno ()));
115 0 : zmq_close (data->zmqSubscriber);
116 0 : data->zmqSubscriber = NULL;
117 0 : return;
118 : }
119 : }
120 :
121 4 : if (!data->zmqAdapter)
122 : {
123 : // attach ZeroMq adater and wait for socket to be writable
124 4 : data->zmqAdapter = elektraIoAdapterZeroMqAttach (data->zmqSubscriber, data->ioBinding, ELEKTRA_IO_ADAPTER_ZEROMQCB_READ,
125 : zeroMqRecvSocketReadable, data);
126 4 : if (!data->zmqAdapter)
127 : {
128 : ELEKTRA_LOG_WARNING ("could not attach zmq adapter");
129 0 : zmq_close (data->zmqSubscriber);
130 0 : data->zmqSubscriber = NULL;
131 0 : return;
132 : }
133 : }
134 : }
135 :
136 : /**
137 : * @internal
138 : * Cleanup ZeroMq.
139 : *
140 : * @param data plugin data
141 : */
142 4 : void elektraZeroMqRecvTeardown (ElektraZeroMqRecvPluginData * data)
143 : {
144 4 : if (data->zmqAdapter)
145 : {
146 4 : elektraIoAdapterZeroMqDetach (data->zmqAdapter);
147 4 : data->zmqAdapter = NULL;
148 : }
149 :
150 4 : if (data->zmqSubscriber)
151 : {
152 4 : zmq_close (data->zmqSubscriber);
153 4 : data->zmqSubscriber = NULL;
154 : }
155 :
156 4 : if (data->zmqContext)
157 : {
158 4 : zmq_ctx_destroy (data->zmqContext);
159 4 : data->zmqContext = NULL;
160 : }
161 4 : }
|