ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/libio/misc/hook.c
Revision: 62
Committed: Mon Oct 3 22:23:39 2005 UTC (20 years, 10 months ago) by adx
Content type: text/x-csrc
File size: 6190 byte(s)
Log Message:
- reorganisation goes on, removed external references from libio/mem

File Contents

# User Rev Content
1 adx 61 /*
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 33 2005-10-02 20:50:00Z knight $
24     */
25    
26     #include "stdinc.h"
27 adx 62 #include "client.h"
28 adx 61 #include "hook.h"
29     #include "ircd.h"
30     #include "list.h"
31     #include "memory.h"
32     #include "numeric.h"
33     #include "tools.h"
34     #include "irc_string.h"
35     #include "send.h"
36    
37     dlink_list callback_list = {NULL, NULL, 0};
38    
39     /*
40     * register_callback()
41     *
42     * Creates a new callback.
43     *
44     * inputs:
45     * name - name used to identify the callback
46     * (can be NULL for anonymous callbacks)
47     * func - initial function attached to the chain
48     * (can be NULL to create an empty chain)
49     * output: pointer to Callback structure or NULL if already exists
50     *
51     * NOTE: Once registered, a callback should never be freed!
52     * That's because there may be modules which depend on it
53     * (even if no functions are attached). That's also why
54     * we dynamically allocate the struct here -- we don't want
55     * to allow anyone to place it in module data, which can be
56     * unloaded at any time.
57     */
58     struct Callback *
59     register_callback(const char *name, CBFUNC *func)
60     {
61     struct Callback *cb;
62    
63     if (name != NULL)
64     if ((cb = find_callback(name)) != NULL)
65     {
66     /* re-attaching an empty hook chain? */
67     if (!is_callback_present(cb))
68     {
69     dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
70     return (cb);
71     }
72     return (NULL);
73     }
74    
75     cb = MyMalloc(sizeof(struct Callback));
76     if (func != NULL)
77     dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
78     if (name != NULL)
79     {
80     DupString(cb->name, name);
81     dlinkAdd(cb, &cb->node, &callback_list);
82     }
83     return (cb);
84     }
85    
86     /*
87     * execute_callback()
88     *
89     * Passes control down the callback hook chain.
90     *
91     * inputs:
92     * callback - pointer to Callback structure
93     * param - argument to pass
94     * output: function return value
95     */
96     void *
97     execute_callback(struct Callback *cb, ...)
98     {
99     void *res;
100     va_list args;
101    
102     cb->called++;
103     cb->last = CurrentTime;
104    
105     if (!is_callback_present(cb))
106     return (NULL);
107    
108     va_start(args, cb);
109     res = ((CBFUNC *) cb->chain.head->data)(args);
110     va_end(args);
111     return (res);
112     }
113    
114     /*
115     * pass_callback()
116     *
117     * Called by a hook function to pass code flow further
118     * in the hook chain.
119     *
120     * inputs:
121     * this_hook - pointer to dlink_node of the current hook function
122     * ... - (original or modified) arguments to be passed
123     * output: callback return value
124     */
125     void *
126     pass_callback(dlink_node *this_hook, ...)
127     {
128     void *res;
129     va_list args;
130    
131     if (this_hook->next == NULL)
132     return (NULL); /* reached the last one */
133    
134     va_start(args, this_hook);
135     res = ((CBFUNC *) this_hook->next->data)(args);
136     va_end(args);
137     return (res);
138     }
139    
140     /*
141     * find_callback()
142     *
143     * Finds a named callback.
144     *
145     * inputs:
146     * name - name of the callback
147     * output: pointer to Callback structure or NULL if not found
148     */
149     struct Callback *
150     find_callback(const char *name)
151     {
152     struct Callback *cb;
153     dlink_node *ptr;
154    
155     DLINK_FOREACH(ptr, callback_list.head)
156     {
157     cb = ptr->data;
158     if (!irccmp(cb->name, name))
159     return (cb);
160     }
161    
162     return (NULL);
163     }
164    
165     /*
166     * install_hook()
167     *
168     * Installs a hook for the given callback.
169     *
170     * inputs:
171     * cb - pointer to Callback structure
172     * hook - address of hook function
173     * output: pointer to dlink_node of the hook (used when
174     * passing control to the next hook in the chain);
175     * valid till uninstall_hook() is called
176     *
177     * NOTE: The new hook is installed at the beginning of the chain,
178     * so it has full control over functions installed earlier.
179     */
180     dlink_node *
181     install_hook(struct Callback *cb, CBFUNC *hook)
182     {
183     dlink_node *node = MyMalloc(sizeof(dlink_node));
184    
185     dlinkAdd(hook, node, &cb->chain);
186     return (node);
187     }
188    
189     /*
190     * uninstall_hook()
191     *
192     * Removes a specific hook for the given callback.
193     *
194     * inputs:
195     * cb - pointer to Callback structure
196     * hook - address of hook function
197     * output: none
198     */
199     void
200     uninstall_hook(struct Callback *cb, CBFUNC *hook)
201     {
202     /* let it core if not found */
203     dlink_node *ptr = dlinkFind(&cb->chain, hook);
204    
205     dlinkDelete(ptr, &cb->chain);
206     MyFree(ptr);
207     }
208    
209     /*
210     * stats_hooks()
211     *
212     * Displays registered callbacks and lengths of their hook chains.
213     * (This is the handler of /stats h)
214     *
215     * inputs:
216     * source_p - pointer to struct Client
217     * output: none
218     */
219     void
220     stats_hooks(struct Client *source_p)
221     {
222     dlink_node *ptr;
223     struct Callback *cb;
224     char lastused[32];
225    
226     sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
227     RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
228     sendto_one(source_p, ":%s %d %s : ------------------------------------"
229     "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
230    
231     DLINK_FOREACH(ptr, callback_list.head)
232     {
233     cb = ptr->data;
234    
235     if (cb->last != 0)
236     snprintf(lastused, sizeof(lastused), "%d seconds ago",
237     (int) (CurrentTime - cb->last));
238     else
239     strcpy(lastused, "NEVER");
240    
241     sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
242     RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
243     dlink_list_length(&cb->chain));
244     }
245    
246     sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
247     source_p->name);
248     }

Properties

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