ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/hook.c
Revision: 157
Committed: Tue Oct 18 06:33:24 2005 UTC (18 years, 5 months ago) by adx
Content type: text/x-csrc
File size: 6042 byte(s)
Log Message:
- MFC: fixed register_callback

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * hook.c: Provides a generic event hooking interface.
4 *
5 * Copyright (C) 2003 Piotr Nizynski, Advanced IRC Services Project Team
6 * Copyright (C) 2005 Hybrid Development Team
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 * $Id$
24 */
25
26 #include "stdinc.h"
27 #include "hook.h"
28 #include "ircd.h"
29 #include "list.h"
30 #include "memory.h"
31 #include "numeric.h"
32 #include "tools.h"
33 #include "irc_string.h"
34 #include "send.h"
35
36 dlink_list callback_list = {NULL, NULL, 0};
37
38 /*
39 * register_callback()
40 *
41 * Creates a new callback.
42 *
43 * inputs:
44 * name - name used to identify the callback
45 * (can be NULL for anonymous callbacks)
46 * func - initial function attached to the chain
47 * (can be NULL to create an empty chain)
48 * output: pointer to Callback structure or NULL if already exists
49 *
50 * NOTE: Once registered, a callback should never be freed!
51 * That's because there may be modules which depend on it
52 * (even if no functions are attached). That's also why
53 * we dynamically allocate the struct here -- we don't want
54 * to allow anyone to place it in module data, which can be
55 * unloaded at any time.
56 */
57 struct Callback *
58 register_callback(const char *name, CBFUNC *func)
59 {
60 struct Callback *cb;
61
62 if (name != NULL)
63 if ((cb = find_callback(name)) != NULL)
64 {
65 if (func != NULL)
66 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
67 return (NULL);
68 }
69
70 cb = MyMalloc(sizeof(struct Callback));
71 if (func != NULL)
72 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
73 if (name != NULL)
74 {
75 DupString(cb->name, name);
76 dlinkAdd(cb, &cb->node, &callback_list);
77 }
78 return (cb);
79 }
80
81 /*
82 * execute_callback()
83 *
84 * Passes control down the callback hook chain.
85 *
86 * inputs:
87 * callback - pointer to Callback structure
88 * param - argument to pass
89 * output: function return value
90 */
91 void *
92 execute_callback(struct Callback *cb, ...)
93 {
94 void *res;
95 va_list args;
96
97 cb->called++;
98 cb->last = CurrentTime;
99
100 if (!is_callback_present(cb))
101 return (NULL);
102
103 va_start(args, cb);
104 res = ((CBFUNC *) cb->chain.head->data)(args);
105 va_end(args);
106 return (res);
107 }
108
109 /*
110 * pass_callback()
111 *
112 * Called by a hook function to pass code flow further
113 * in the hook chain.
114 *
115 * inputs:
116 * this_hook - pointer to dlink_node of the current hook function
117 * ... - (original or modified) arguments to be passed
118 * output: callback return value
119 */
120 void *
121 pass_callback(dlink_node *this_hook, ...)
122 {
123 void *res;
124 va_list args;
125
126 if (this_hook->next == NULL)
127 return (NULL); /* reached the last one */
128
129 va_start(args, this_hook);
130 res = ((CBFUNC *) this_hook->next->data)(args);
131 va_end(args);
132 return (res);
133 }
134
135 /*
136 * find_callback()
137 *
138 * Finds a named callback.
139 *
140 * inputs:
141 * name - name of the callback
142 * output: pointer to Callback structure or NULL if not found
143 */
144 struct Callback *
145 find_callback(const char *name)
146 {
147 struct Callback *cb;
148 dlink_node *ptr;
149
150 DLINK_FOREACH(ptr, callback_list.head)
151 {
152 cb = ptr->data;
153 if (!irccmp(cb->name, name))
154 return (cb);
155 }
156
157 return (NULL);
158 }
159
160 /*
161 * install_hook()
162 *
163 * Installs a hook for the given callback.
164 *
165 * inputs:
166 * cb - pointer to Callback structure
167 * hook - address of hook function
168 * output: pointer to dlink_node of the hook (used when
169 * passing control to the next hook in the chain);
170 * valid till uninstall_hook() is called
171 *
172 * NOTE: The new hook is installed at the beginning of the chain,
173 * so it has full control over functions installed earlier.
174 */
175 dlink_node *
176 install_hook(struct Callback *cb, CBFUNC *hook)
177 {
178 dlink_node *node = MyMalloc(sizeof(dlink_node));
179
180 dlinkAdd(hook, node, &cb->chain);
181 return (node);
182 }
183
184 /*
185 * uninstall_hook()
186 *
187 * Removes a specific hook for the given callback.
188 *
189 * inputs:
190 * cb - pointer to Callback structure
191 * hook - address of hook function
192 * output: none
193 */
194 void
195 uninstall_hook(struct Callback *cb, CBFUNC *hook)
196 {
197 /* let it core if not found */
198 dlink_node *ptr = dlinkFind(&cb->chain, hook);
199
200 dlinkDelete(ptr, &cb->chain);
201 MyFree(ptr);
202 }
203
204 /*
205 * stats_hooks()
206 *
207 * Displays registered callbacks and lengths of their hook chains.
208 * (This is the handler of /stats h)
209 *
210 * inputs:
211 * source_p - pointer to struct Client
212 * output: none
213 */
214 void
215 stats_hooks(struct Client *source_p)
216 {
217 dlink_node *ptr;
218 struct Callback *cb;
219 char lastused[32];
220
221 sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
222 RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
223 sendto_one(source_p, ":%s %d %s : ------------------------------------"
224 "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
225
226 DLINK_FOREACH(ptr, callback_list.head)
227 {
228 cb = ptr->data;
229
230 if (cb->last != 0)
231 snprintf(lastused, sizeof(lastused), "%d seconds ago",
232 (int) (CurrentTime - cb->last));
233 else
234 strcpy(lastused, "NEVER");
235
236 sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
237 RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
238 dlink_list_length(&cb->chain));
239 }
240
241 sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
242 source_p->name);
243 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision