ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/hook.c
Revision: 3334
Committed: Wed Apr 16 16:42:54 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 5752 byte(s)
Log Message:
- Replaced strcpy() with strlcpy() in some places

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)
61 {
62 if ((cb = find_callback(name)))
63 {
64 if (func)
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)
74 dlinkAdd(func, MyMalloc(sizeof(dlink_node)), &cb->chain);
75
76 if (name)
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 if (!irccmp(((struct Callback *)ptr->data)->name, name))
142 return ptr->data;
143
144 return NULL;
145 }
146
147 /*! \brief Installs a hook for the given callback.
148 *
149 * The new hook is installed at the beginning of the chain,
150 * so it has full control over functions installed earlier.
151 *
152 * \param cb Pointer to Callback structure
153 * \param hook Address of hook function
154 * \return Pointer to dlink_node of the hook (used when passing
155 * control to the next hook in the chain);
156 * valid till uninstall_hook() is called
157 */
158 dlink_node *
159 install_hook(struct Callback *cb, CBFUNC *hook)
160 {
161 dlink_node *node = MyMalloc(sizeof(dlink_node));
162
163 dlinkAdd(hook, node, &cb->chain);
164 return node;
165 }
166
167 /*! \brief Removes a specific hook for the given callback.
168 * \param cb Pointer to Callback structure
169 * \param hook Address of hook function
170 */
171 void
172 uninstall_hook(struct Callback *cb, CBFUNC *hook)
173 {
174 /* Let it core if not found */
175 dlink_node *ptr = dlinkFind(&cb->chain, hook);
176
177 dlinkDelete(ptr, &cb->chain);
178 MyFree(ptr);
179 }
180
181 /*! \brief Displays registered callbacks and lengths of their hook chains.
182 * (This is the handler of /stats h)
183 * \param source_p Pointer to struct Client
184 */
185 void
186 stats_hooks(struct Client *source_p)
187 {
188 char lastused[IRCD_BUFSIZE] = "";
189 const dlink_node *ptr = NULL;
190
191 sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
192 RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
193 sendto_one(source_p, ":%s %d %s : ------------------------------------"
194 "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
195
196 DLINK_FOREACH(ptr, callback_list.head)
197 {
198 const struct Callback *cb = ptr->data;
199
200 if (cb->last)
201 snprintf(lastused, sizeof(lastused), "%d seconds ago",
202 (int)(CurrentTime - cb->last));
203 else
204 strlcpy(lastused, "NEVER", sizeof(lastused));
205
206 sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
207 RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
208 dlink_list_length(&cb->chain));
209 }
210 }

Properties

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