Line data Source code
1 : /*
2 : SSSD
3 :
4 : Data Provider Process - Callback
5 :
6 : Authors:
7 :
8 : Stephen Gallagher <sgallagh@redhat.com>
9 : Sumit Bose <sbose@redhat.com>
10 :
11 : Copyright (C) 2010 Red Hat
12 :
13 : This program is free software; you can redistribute it and/or modify
14 : it under the terms of the GNU General Public License as published by
15 : the Free Software Foundation; either version 3 of the License, or
16 : (at your option) any later version.
17 :
18 : This program is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : GNU General Public License for more details.
22 :
23 : You should have received a copy of the GNU General Public License
24 : along with this program. If not, see <http://www.gnu.org/licenses/>.
25 : */
26 :
27 : #include "util/util.h"
28 : #include "providers/backend.h"
29 :
30 : struct be_cb {
31 : struct be_cb *prev;
32 : struct be_cb *next;
33 :
34 : be_callback_t cb;
35 : void *pvt;
36 :
37 : struct be_cb **list;
38 : struct be_ctx *be;
39 : };
40 :
41 : struct be_cb_ctx {
42 : struct be_ctx *be;
43 : struct be_cb *callback;
44 : };
45 :
46 0 : static int cb_destructor(TALLOC_CTX *ptr)
47 : {
48 0 : struct be_cb *cb = talloc_get_type(ptr, struct be_cb);
49 0 : DLIST_REMOVE(*(cb->list), cb);
50 0 : return 0;
51 : }
52 :
53 0 : static int be_add_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
54 : be_callback_t cb, void *pvt, struct be_cb **cb_list,
55 : struct be_cb **return_cb)
56 : {
57 : struct be_cb *new_cb;
58 :
59 0 : if (!ctx || !cb) {
60 0 : return EINVAL;
61 : }
62 :
63 0 : new_cb = talloc(mem_ctx, struct be_cb);
64 0 : if (!new_cb) {
65 0 : return ENOMEM;
66 : }
67 :
68 0 : new_cb->cb = cb;
69 0 : new_cb->pvt = pvt;
70 0 : new_cb->list = cb_list;
71 0 : new_cb->be = ctx;
72 :
73 0 : DLIST_ADD(*cb_list, new_cb);
74 :
75 0 : talloc_set_destructor((TALLOC_CTX *) new_cb, cb_destructor);
76 :
77 0 : if (return_cb) {
78 0 : *return_cb = new_cb;
79 : }
80 :
81 0 : return EOK;
82 : }
83 :
84 0 : static void be_run_cb_step(struct tevent_context *ev, struct tevent_timer *te,
85 : struct timeval current_time, void *pvt)
86 : {
87 0 : struct be_cb_ctx *cb_ctx = talloc_get_type(pvt, struct be_cb_ctx);
88 : struct be_cb *next_cb;
89 : struct tevent_timer *tev;
90 : struct timeval soon;
91 :
92 : /* Store next callback in case this callback frees itself */
93 0 : next_cb = cb_ctx->callback->next;
94 :
95 : /* Call the callback */
96 0 : cb_ctx->callback->cb(cb_ctx->callback->pvt);
97 :
98 0 : if (next_cb) {
99 0 : cb_ctx->callback = next_cb;
100 :
101 : /* Delay 30ms so we don't block any other events */
102 0 : soon = tevent_timeval_current_ofs(0, 30000);
103 0 : tev = tevent_add_timer(cb_ctx->be->ev, cb_ctx, soon,
104 : be_run_cb_step,
105 : cb_ctx);
106 0 : if (!tev) {
107 0 : DEBUG(SSSDBG_FATAL_FAILURE,
108 : "Out of memory. Could not invoke callbacks\n");
109 0 : goto final;
110 : }
111 0 : return;
112 : }
113 :
114 : final:
115 : /* Steal the timer event onto the be_ctx so it doesn't
116 : * get freed with the cb_ctx
117 : */
118 0 : talloc_steal(cb_ctx->be, te);
119 0 : talloc_free(cb_ctx);
120 : }
121 :
122 0 : static errno_t be_run_cb(struct be_ctx *be, struct be_cb *cb_list)
123 : {
124 : struct timeval soon;
125 : struct tevent_timer *te;
126 : struct be_cb_ctx *cb_ctx;
127 :
128 0 : if (cb_list == NULL) {
129 0 : return EOK;
130 : }
131 :
132 0 : cb_ctx = talloc(be, struct be_cb_ctx);
133 0 : if (!cb_ctx) {
134 0 : DEBUG(SSSDBG_FATAL_FAILURE,
135 : "Out of memory. Could not invoke callbacks\n");
136 0 : return ENOMEM;
137 : }
138 0 : cb_ctx->be = be;
139 0 : cb_ctx->callback = cb_list;
140 :
141 : /* Delay 30ms so we don't block any other events */
142 0 : soon = tevent_timeval_current_ofs(0, 30000);
143 0 : te = tevent_add_timer(be->ev, cb_ctx, soon,
144 : be_run_cb_step,
145 : cb_ctx);
146 0 : if (!te) {
147 0 : DEBUG(SSSDBG_FATAL_FAILURE,
148 : "Out of memory. Could not invoke callbacks\n");
149 0 : talloc_free(cb_ctx);
150 0 : return ENOMEM;
151 : }
152 :
153 0 : return EOK;
154 : }
155 :
156 0 : int be_add_reconnect_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
157 : void *pvt, struct be_cb **reconnect_cb)
158 : {
159 : int ret;
160 :
161 0 : ret = be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->reconnect_cb_list, reconnect_cb);
162 0 : if (ret != EOK) {
163 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_add_cb failed.\n");
164 0 : return ret;
165 : }
166 :
167 0 : return EOK;
168 : }
169 :
170 0 : void be_run_reconnect_cb(struct be_ctx *be)
171 : {
172 0 : struct be_cb *callback = be->reconnect_cb_list;
173 : struct be_cb *next_cb;
174 :
175 0 : if (callback) {
176 0 : DEBUG(SSSDBG_TRACE_FUNC, "Reconnecting. Running callbacks.\n");
177 :
178 : /**
179 : * Call the callback: we have to call this right away
180 : * so the provider doesn't go into offline even for
181 : * a little while
182 : */
183 : do {
184 : /* Store next callback in case this callback frees itself */
185 0 : next_cb = callback->next;
186 :
187 0 : callback->cb(callback->pvt);
188 0 : callback = next_cb;
189 0 : } while(callback != NULL);
190 : } else {
191 0 : DEBUG(SSSDBG_TRACE_INTERNAL, "Reconnect call back list is empty, nothing to do.\n");
192 : }
193 0 : }
194 :
195 0 : int be_add_online_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
196 : void *pvt, struct be_cb **online_cb)
197 : {
198 : int ret;
199 :
200 0 : ret = be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->online_cb_list, online_cb);
201 0 : if (ret != EOK) {
202 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_add_cb failed.\n");
203 0 : return ret;
204 : }
205 :
206 : /* Make sure we run the callback for the first
207 : * connection after startup.
208 : */
209 0 : ctx->run_online_cb = true;
210 :
211 0 : return EOK;
212 : }
213 :
214 0 : void be_run_online_cb(struct be_ctx *be) {
215 : int ret;
216 :
217 0 : if (be->run_online_cb) {
218 : /* Reset the flag. We only want to run these
219 : * callbacks when transitioning to online
220 : */
221 0 : be->run_online_cb = false;
222 :
223 0 : if (be->online_cb_list) {
224 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Going online. Running callbacks.\n");
225 :
226 0 : ret = be_run_cb(be, be->online_cb_list);
227 0 : if (ret != EOK) {
228 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_run_cb failed.\n");
229 : }
230 :
231 : } else {
232 0 : DEBUG(SSSDBG_TRACE_ALL,
233 : "Online call back list is empty, nothing to do.\n");
234 : }
235 : }
236 0 : }
237 :
238 0 : int be_add_unconditional_online_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,
239 : be_callback_t cb, void *pvt,
240 : struct be_cb **unconditional_online_cb)
241 : {
242 0 : return be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->unconditional_online_cb_list,
243 : unconditional_online_cb);
244 : }
245 :
246 0 : void be_run_unconditional_online_cb(struct be_ctx *be)
247 : {
248 : int ret;
249 :
250 0 : if (be->unconditional_online_cb_list) {
251 0 : DEBUG(SSSDBG_TRACE_FUNC, "Running unconditional online callbacks.\n");
252 :
253 0 : ret = be_run_cb(be, be->unconditional_online_cb_list);
254 0 : if (ret != EOK) {
255 0 : DEBUG(SSSDBG_OP_FAILURE, "be_run_cb failed.\n");
256 : }
257 :
258 : } else {
259 0 : DEBUG(SSSDBG_TRACE_ALL,
260 : "List of unconditional online callbacks is empty, " \
261 : "nothing to do.\n");
262 : }
263 0 : }
264 :
265 0 : int be_add_offline_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
266 : void *pvt, struct be_cb **offline_cb)
267 : {
268 0 : return be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->offline_cb_list, offline_cb);
269 : }
270 :
271 1 : void be_run_offline_cb(struct be_ctx *be) {
272 : int ret;
273 :
274 1 : if (be->offline_cb_list) {
275 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Going offline. Running callbacks.\n");
276 :
277 0 : ret = be_run_cb(be, be->offline_cb_list);
278 0 : if (ret != EOK) {
279 0 : DEBUG(SSSDBG_CRIT_FAILURE, "be_run_cb failed.\n");
280 : }
281 :
282 : } else {
283 1 : DEBUG(SSSDBG_TRACE_ALL,
284 : "Offline call back list is empty, nothing to do.\n");
285 : }
286 1 : }
|