Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief I/O Adapter for D-Bus.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 : #include <kdbassert.h>
9 : #include <kdbhelper.h>
10 : #include <kdbio/adapters/zeromq.h>
11 : #include <kdblogger.h>
12 :
13 : #include <stdlib.h>
14 : #include <string.h>
15 :
16 : typedef struct _ElektraIoAdapterZeroMqHandle
17 : {
18 : ElektraIoInterface * ioBinding;
19 : ElektraIoIdleOperation * dispatchIdle;
20 : ElektraIoFdOperation * fdOp;
21 :
22 : void * socket;
23 :
24 : ElektraIoAdapterZeroMqCallbackType type;
25 : ElektraIoAdapterZeroMqCallback callback;
26 : void * callbackContext;
27 :
28 : } _ElektraIoAdapterZeroMqHandle;
29 :
30 6 : static void zmqAdapterDispatch (_ElektraIoAdapterZeroMqHandle * handle)
31 : {
32 6 : ElektraIoIdleOperation * dispatchIdle = handle->dispatchIdle;
33 :
34 : // Check if socket is readable or writable
35 6 : uint events = 0;
36 6 : size_t events_len = sizeof (events);
37 6 : zmq_getsockopt (handle->socket, ZMQ_EVENTS, &events, &events_len);
38 :
39 6 : if ((events & ZMQ_POLLIN) && handle->type == ELEKTRA_IO_ADAPTER_ZEROMQCB_READ)
40 : {
41 2 : handle->callback (handle->socket, handle->callbackContext);
42 : }
43 6 : if ((events & ZMQ_POLLOUT) && handle->type == ELEKTRA_IO_ADAPTER_ZEROMQCB_WRITE)
44 : {
45 0 : handle->callback (handle->socket, handle->callbackContext);
46 : }
47 :
48 6 : if (!(events & ZMQ_POLLIN) && !(events & ZMQ_POLLOUT))
49 : {
50 : // Disable idle, nothing to do anymore
51 4 : elektraIoIdleSetEnabled (dispatchIdle, 0);
52 4 : elektraIoBindingUpdateIdle (dispatchIdle);
53 : }
54 6 : }
55 :
56 0 : static void zmqAdapterIdleCallback (ElektraIoIdleOperation * idleOp)
57 : {
58 0 : _ElektraIoAdapterZeroMqHandle * handle = elektraIoIdleGetData (idleOp);
59 0 : ELEKTRA_NOT_NULL (handle);
60 0 : zmqAdapterDispatch (handle);
61 0 : }
62 :
63 6 : static void zmqAdapterFdCallback (ElektraIoFdOperation * fdOp, int flags)
64 : {
65 6 : _ElektraIoAdapterZeroMqHandle * handle = elektraIoFdGetData (fdOp);
66 6 : ELEKTRA_NOT_NULL (handle);
67 6 : ElektraIoIdleOperation * dispatchIdle = handle->dispatchIdle;
68 :
69 6 : if (flags & ELEKTRA_IO_READABLE || flags & ELEKTRA_IO_WRITABLE)
70 : {
71 6 : elektraIoIdleSetEnabled (dispatchIdle, 1);
72 6 : elektraIoBindingUpdateIdle (dispatchIdle);
73 : }
74 :
75 : // Dispatch available data
76 6 : zmqAdapterDispatch (handle);
77 6 : }
78 :
79 4 : ElektraIoAdapterZeroMqHandle * elektraIoAdapterZeroMqAttach (void * socket, ElektraIoInterface * ioBinding,
80 : ElektraIoAdapterZeroMqCallbackType type,
81 : ElektraIoAdapterZeroMqCallback callback, void * context)
82 : {
83 4 : if (socket == NULL)
84 : {
85 : ELEKTRA_LOG_WARNING ("socket cannot be null");
86 : return NULL;
87 : }
88 4 : if (ioBinding == NULL)
89 : {
90 : ELEKTRA_LOG_WARNING ("ioBinding cannot be null");
91 : return NULL;
92 : }
93 4 : if (callback == NULL)
94 : {
95 : ELEKTRA_LOG_WARNING ("callback cannot be null");
96 : return NULL;
97 : }
98 :
99 4 : _ElektraIoAdapterZeroMqHandle * handle = elektraMalloc (sizeof (*handle));
100 4 : if (!handle)
101 : {
102 : return NULL;
103 : }
104 4 : handle->ioBinding = ioBinding;
105 4 : handle->socket = socket;
106 4 : handle->type = type;
107 4 : handle->callback = callback;
108 4 : handle->callbackContext = context;
109 :
110 : int fdOpFlags;
111 4 : switch (type)
112 : {
113 : case ELEKTRA_IO_ADAPTER_ZEROMQCB_READ:
114 : fdOpFlags = ELEKTRA_IO_READABLE;
115 : break;
116 : case ELEKTRA_IO_ADAPTER_ZEROMQCB_WRITE:
117 0 : fdOpFlags = ELEKTRA_IO_WRITABLE;
118 0 : break;
119 : default:
120 : ELEKTRA_LOG_WARNING ("invalid callback type: %d", type);
121 : return NULL;
122 : break;
123 : }
124 :
125 : // Add sockets file descriptor to I/O binding
126 : int fd;
127 4 : size_t fd_len = sizeof (fd);
128 4 : if (zmq_getsockopt (socket, ZMQ_FD, &fd, &fd_len) != 0)
129 : {
130 : ELEKTRA_LOG_WARNING ("zmq_getsockopt failed: could not get file descriptor from socket");
131 : return NULL;
132 : }
133 4 : ElektraIoFdOperation * fdOp = elektraIoNewFdOperation (fd, fdOpFlags, 1, zmqAdapterFdCallback, handle);
134 4 : if (fdOp == NULL)
135 : {
136 0 : elektraFree (handle);
137 0 : return NULL;
138 : }
139 4 : handle->fdOp = fdOp;
140 4 : if (!elektraIoBindingAddFd (ioBinding, fdOp))
141 : {
142 0 : elektraFree (fdOp);
143 0 : elektraFree (handle);
144 0 : return NULL;
145 : }
146 :
147 : // Add timeout for reading messages
148 4 : ElektraIoIdleOperation * dispatchIdle = elektraIoNewIdleOperation (0, zmqAdapterIdleCallback, handle);
149 4 : if (!dispatchIdle)
150 : {
151 0 : elektraIoBindingRemoveFd (fdOp);
152 0 : elektraFree (fdOp);
153 0 : elektraFree (handle);
154 0 : return NULL;
155 : }
156 4 : handle->dispatchIdle = dispatchIdle;
157 4 : if (!elektraIoBindingAddIdle (ioBinding, dispatchIdle))
158 : {
159 0 : elektraFree (dispatchIdle);
160 0 : elektraIoBindingRemoveFd (fdOp);
161 0 : elektraFree (fdOp);
162 0 : elektraFree (handle);
163 0 : return NULL;
164 : }
165 :
166 : return handle;
167 : }
168 :
169 0 : void elektraIoAdapterZeroMqSetContext (ElektraIoAdapterZeroMqHandle * handle, void * context)
170 : {
171 0 : handle->callbackContext = context;
172 0 : }
173 :
174 4 : int elektraIoAdapterZeroMqDetach (ElektraIoAdapterZeroMqHandle * handle)
175 : {
176 :
177 4 : if (!elektraIoBindingRemoveIdle (handle->dispatchIdle))
178 : {
179 : ELEKTRA_LOG_WARNING ("could not remove idle operation");
180 : }
181 4 : if (!elektraIoBindingRemoveFd (handle->fdOp))
182 : {
183 : ELEKTRA_LOG_WARNING ("could not remove fd operation");
184 : }
185 4 : elektraFree (handle->dispatchIdle);
186 4 : elektraFree (handle->fdOp);
187 4 : elektraFree (handle);
188 :
189 4 : return 1;
190 : }
|