ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/hook.c
Revision: 713
Committed: Wed Jul 12 12:37:35 2006 UTC (17 years, 9 months ago) by michael
Content type: text/x-csrc
File size: 6044 byte(s)
Log Message:
- fixed core on MODRESTART as reported by xZ/CoolCold

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
24 adx 30 */
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 adx 157 if (func != NULL)
66 michael 713 dlinkAddTail(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
67     return (cb);
68 adx 30 }
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