ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/hook.c
Revision: 30
Committed: Sun Oct 2 20:03:27 2005 UTC (18 years, 5 months ago) by adx
Content type: text/x-csrc
File size: 6174 byte(s)
Log Message:
- imported sources
- can be moved later according to the directory/branching scheme,
  but we need the svn up

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: hook.c,v 7.33 2005/09/18 20:09:03 adx Exp $
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 /* re-attaching an empty hook chain? */
66 if (!is_callback_present(cb))
67 {
68 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
69 return (cb);
70 }
71 return (NULL);
72 }
73
74 cb = MyMalloc(sizeof(struct Callback));
75 if (func != NULL)
76 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
77 if (name != NULL)
78 {
79 DupString(cb->name, name);
80 dlinkAdd(cb, &cb->node, &callback_list);
81 }
82 return (cb);
83 }
84
85 /*
86 * execute_callback()
87 *
88 * Passes control down the callback hook chain.
89 *
90 * inputs:
91 * callback - pointer to Callback structure
92 * param - argument to pass
93 * output: function return value
94 */
95 void *
96 execute_callback(struct Callback *cb, ...)
97 {
98 void *res;
99 va_list args;
100
101 cb->called++;
102 cb->last = CurrentTime;
103
104 if (!is_callback_present(cb))
105 return (NULL);
106
107 va_start(args, cb);
108 res = ((CBFUNC *) cb->chain.head->data)(args);
109 va_end(args);
110 return (res);
111 }
112
113 /*
114 * pass_callback()
115 *
116 * Called by a hook function to pass code flow further
117 * in the hook chain.
118 *
119 * inputs:
120 * this_hook - pointer to dlink_node of the current hook function
121 * ... - (original or modified) arguments to be passed
122 * output: callback return value
123 */
124 void *
125 pass_callback(dlink_node *this_hook, ...)
126 {
127 void *res;
128 va_list args;
129
130 if (this_hook->next == NULL)
131 return (NULL); /* reached the last one */
132
133 va_start(args, this_hook);
134 res = ((CBFUNC *) this_hook->next->data)(args);
135 va_end(args);
136 return (res);
137 }
138
139 /*
140 * find_callback()
141 *
142 * Finds a named callback.
143 *
144 * inputs:
145 * name - name of the callback
146 * output: pointer to Callback structure or NULL if not found
147 */
148 struct Callback *
149 find_callback(const char *name)
150 {
151 struct Callback *cb;
152 dlink_node *ptr;
153
154 DLINK_FOREACH(ptr, callback_list.head)
155 {
156 cb = ptr->data;
157 if (!irccmp(cb->name, name))
158 return (cb);
159 }
160
161 return (NULL);
162 }
163
164 /*
165 * install_hook()
166 *
167 * Installs a hook for the given callback.
168 *
169 * inputs:
170 * cb - pointer to Callback structure
171 * hook - address of hook function
172 * output: pointer to dlink_node of the hook (used when
173 * passing control to the next hook in the chain);
174 * valid till uninstall_hook() is called
175 *
176 * NOTE: The new hook is installed at the beginning of the chain,
177 * so it has full control over functions installed earlier.
178 */
179 dlink_node *
180 install_hook(struct Callback *cb, CBFUNC *hook)
181 {
182 dlink_node *node = MyMalloc(sizeof(dlink_node));
183
184 dlinkAdd(hook, node, &cb->chain);
185 return (node);
186 }
187
188 /*
189 * uninstall_hook()
190 *
191 * Removes a specific hook for the given callback.
192 *
193 * inputs:
194 * cb - pointer to Callback structure
195 * hook - address of hook function
196 * output: none
197 */
198 void
199 uninstall_hook(struct Callback *cb, CBFUNC *hook)
200 {
201 /* let it core if not found */
202 dlink_node *ptr = dlinkFind(&cb->chain, hook);
203
204 dlinkDelete(ptr, &cb->chain);
205 MyFree(ptr);
206 }
207
208 /*
209 * stats_hooks()
210 *
211 * Displays registered callbacks and lengths of their hook chains.
212 * (This is the handler of /stats h)
213 *
214 * inputs:
215 * source_p - pointer to struct Client
216 * output: none
217 */
218 void
219 stats_hooks(struct Client *source_p)
220 {
221 dlink_node *ptr;
222 struct Callback *cb;
223 char lastused[32];
224
225 sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
226 RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
227 sendto_one(source_p, ":%s %d %s : ------------------------------------"
228 "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
229
230 DLINK_FOREACH(ptr, callback_list.head)
231 {
232 cb = ptr->data;
233
234 if (cb->last != 0)
235 snprintf(lastused, sizeof(lastused), "%d seconds ago",
236 (int) (CurrentTime - cb->last));
237 else
238 strcpy(lastused, "NEVER");
239
240 sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
241 RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
242 dlink_list_length(&cb->chain));
243 }
244
245 sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
246 source_p->name);
247 }

Properties

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