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/dp_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   	static int cb_destructor(TALLOC_CTX *ptr)
47   	{
48   	    struct be_cb *cb = talloc_get_type(ptr, struct be_cb);
49   	    DLIST_REMOVE(cb->list, cb);
50   	    return 0;
51   	}
52   	
53   	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   	    if (!ctx || !cb) {
60   	        return EINVAL;
61   	    }
62   	
63   	    new_cb = talloc(mem_ctx, struct be_cb);
64   	    if (!new_cb) {
65   	        return ENOMEM;
66   	    }
67   	
68   	    new_cb->cb = cb;
69   	    new_cb->pvt = pvt;
70   	    new_cb->list = *cb_list;
71   	    new_cb->be = ctx;
72   	
73   	    DLIST_ADD(*cb_list, new_cb);
74   	
75   	    talloc_set_destructor((TALLOC_CTX *) new_cb, cb_destructor);
76   	
77   	    if (return_cb) {
78   	        *return_cb = new_cb;
79   	    }
80   	
81   	    return EOK;
82   	}
83   	
84   	static void be_run_cb_step(struct tevent_context *ev, struct tevent_timer *te,
85   	                           struct timeval current_time, void *pvt)
86   	{
87   	    struct be_cb_ctx *cb_ctx = talloc_get_type(pvt, struct be_cb_ctx);
88   	    struct tevent_timer *tev;
89   	    struct timeval soon;
90   	
91   	    /* Call the callback */
92   	    cb_ctx->callback->cb(cb_ctx->callback->pvt);
93   	
94   	    if (cb_ctx->callback->next) {
95   	        cb_ctx->callback = cb_ctx->callback->next;
96   	
97   	        /* Delay 30ms so we don't block any other events */
98   	        soon = tevent_timeval_current_ofs(0, 30000);
Event returned_pointer: Pointer "tev" returned by "_tevent_add_timer(cb_ctx->be->ev, cb_ctx, soon, be_run_cb_step, cb_ctx, &"be_run_cb_step", &"providers/data_provider_callbacks.c:99")" is never used.
99   	        tev = tevent_add_timer(cb_ctx->be->ev, cb_ctx, soon,
100  	                               be_run_cb_step,
101  	                               cb_ctx);
102  	        if (!te) {
103  	            DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
104  	            goto final;
105  	        }
106  	        return;
107  	    }
108  	
109  	final:
110  	    /* Steal the timer event onto the be_ctx so it doesn't
111  	     * get freed with the cb_ctx
112  	     */
113  	    talloc_steal(cb_ctx->be, te);
114  	    talloc_free(cb_ctx);
115  	}
116  	
117  	static errno_t be_run_cb(struct be_ctx *be, struct be_cb *cb_list) {
118  	    struct timeval soon;
119  	    struct tevent_timer *te;
120  	    struct be_cb_ctx *cb_ctx;
121  	
122  	    cb_ctx = talloc(be, struct be_cb_ctx);
123  	    if (!cb_ctx) {
124  	        DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
125  	        return ENOMEM;
126  	    }
127  	    cb_ctx->be = be;
128  	    cb_ctx->callback = cb_list;
129  	
130  	    /* Delay 30ms so we don't block any other events */
131  	    soon = tevent_timeval_current_ofs(0, 30000);
132  	    te = tevent_add_timer(be->ev, cb_ctx, soon,
133  	                          be_run_cb_step,
134  	                          cb_ctx);
135  	    if (!te) {
136  	        DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));
137  	        talloc_free(cb_ctx);
138  	        return ENOMEM;
139  	    }
140  	
141  	    return EOK;
142  	}
143  	
144  	int be_add_online_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
145  	                     void *pvt, struct be_cb **online_cb)
146  	{
147  	    int ret;
148  	
149  	    ret = be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->online_cb_list, online_cb);
150  	    if (ret != EOK) {
151  	        DEBUG(1, ("be_add_cb failed.\n"));
152  	        return ret;
153  	    }
154  	
155  	    /* Make sure we run the callback for the first
156  	     * connection after startup.
157  	     */
158  	    ctx->run_online_cb = true;
159  	
160  	    return EOK;
161  	}
162  	
163  	void be_run_online_cb(struct be_ctx *be) {
164  	    int ret;
165  	
166  	    if (be->run_online_cb) {
167  	        /* Reset the flag. We only want to run these
168  	         * callbacks when transitioning to online
169  	         */
170  	        be->run_online_cb = false;
171  	
172  	        if (be->online_cb_list) {
173  	            DEBUG(3, ("Going online. Running callbacks.\n"));
174  	
175  	            ret = be_run_cb(be, be->online_cb_list);
176  	            if (ret != EOK) {
177  	                DEBUG(1, ("be_run_cb failed.\n"));
178  	            }
179  	
180  	        } else {
181  	            DEBUG(9, ("Online call back list is empty, nothing to do.\n"));
182  	        }
183  	    }
184  	}
185  	
186  	int be_add_offline_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,
187  	                      void *pvt, struct be_cb **offline_cb)
188  	{
189  	    return be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->offline_cb_list, offline_cb);
190  	}
191  	
192  	void be_run_offline_cb(struct be_ctx *be) {
193  	    int ret;
194  	
195  	    if (be->offline_cb_list) {
196  	        DEBUG(3, ("Going offline. Running callbacks.\n"));
197  	
198  	        ret = be_run_cb(be, be->offline_cb_list);
199  	        if (ret != EOK) {
200  	            DEBUG(1, ("be_run_cb failed.\n"));
201  	        }
202  	
203  	    } else {
204  	        DEBUG(9, ("Offline call back list is empty, nothing to do.\n"));
205  	    }
206  	}