ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/hook.c
Revision: 31
Committed: Sun Oct 2 20:34:05 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
File size: 6130 byte(s)
Log Message:
- Fix svn:keywords

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     /* 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"