ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hook.c
Revision: 2846
Committed: Fri Jan 17 16:58:36 2014 UTC (11 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 5785 byte(s)
Log Message:
- hook.h, hook.c: fixed indentation, removed whitespaces/tabs

File Contents

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

Properties

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