ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/watch.c
Revision: 3424
Committed: Wed Apr 30 20:27:25 2014 UTC (11 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 6241 byte(s)
Log Message:
- Fixed possible WATCH core. Fix provided by Adam

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3 *
4 * Copyright (c) 1997 Jukka Santala (Donwulff)
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 watch.c
24 * \brief File including functions for WATCH support
25 * \version $Id$
26 */
27
28 #include "stdinc.h"
29 #include "list.h"
30 #include "client.h"
31 #include "hash.h"
32 #include "irc_string.h"
33 #include "ircd.h"
34 #include "numeric.h"
35 #include "conf.h"
36 #include "send.h"
37 #include "mempool.h"
38 #include "watch.h"
39
40
41 static dlink_list watchTable[HASHSIZE];
42 static mp_pool_t *watch_pool;
43
44 /*! \brief Initializes the watch table
45 */
46 void
47 watch_init(void)
48 {
49 watch_pool = mp_pool_new(sizeof(struct Watch), MP_CHUNK_SIZE_WATCH);
50 }
51
52 /*
53 * Rough figure of the datastructures for watch:
54 *
55 * NOTIFY HASH client_p1
56 * | |- nick1
57 * nick1-|- client_p1 |- nick2
58 * | |- client_p2 client_p3
59 * | |- client_p3 client_p2 |- nick1
60 * | |- nick1
61 * nick2-|- client_p2 |- nick2
62 * |- client_p1
63 */
64
65 /*! \brief Counts up memory used by watch list headers
66 */
67 void
68 watch_count_memory(unsigned int *const count, uint64_t *const bytes)
69 {
70 for (unsigned int i = 0; i < HASHSIZE; ++i)
71 (*count) += dlink_list_length(&watchTable[i]);
72
73 (*bytes) = *count * sizeof(struct Watch);
74 }
75
76 /*! \brief Notifies all clients that have client_p's nick name on
77 * their watch list.
78 * \param client_p Pointer to Client struct
79 * \param reply Numeric to send. Either RPL_LOGON or RPL_LOGOFF
80 */
81 void
82 watch_check_hash(struct Client *client_p, const enum irc_numerics reply)
83 {
84 struct Watch *anptr = NULL;
85 dlink_node *ptr = NULL;
86
87 assert(IsClient(client_p));
88
89 if ((anptr = watch_find_hash(client_p->name)) == NULL)
90 return; /* This nick isn't on watch */
91
92 /* Update the time of last change to item */
93 anptr->lasttime = CurrentTime;
94
95 /* Send notifies out to everybody on the list in header */
96 DLINK_FOREACH(ptr, anptr->watched_by.head)
97 sendto_one_numeric(ptr->data, &me, reply, client_p->name,
98 client_p->username, client_p->host,
99 anptr->lasttime, client_p->info);
100 }
101
102 /*! \brief Looks up the watch table for a given nick
103 * \param name Nick name to look up
104 */
105 struct Watch *
106 watch_find_hash(const char *name)
107 {
108 dlink_node *ptr = NULL;
109
110 DLINK_FOREACH(ptr, watchTable[strhash(name)].head)
111 {
112 struct Watch *anptr = ptr->data;
113
114 if (!irccmp(anptr->nick, name))
115 return anptr;
116 }
117
118 return NULL;
119 }
120
121 /*! \brief Adds a watch entry to client_p's watch list
122 * \param nick Nick name to add
123 * \param client_p Pointer to Client struct
124 */
125 void
126 watch_add_to_hash_table(const char *nick, struct Client *client_p)
127 {
128 struct Watch *anptr = NULL;
129 dlink_node *ptr = NULL;
130
131 /* If found NULL (no header for this nick), make one... */
132 if ((anptr = watch_find_hash(nick)) == NULL)
133 {
134 anptr = mp_pool_get(watch_pool);
135
136 memset(anptr, 0, sizeof(*anptr));
137 anptr->lasttime = CurrentTime;
138 strlcpy(anptr->nick, nick, sizeof(anptr->nick));
139
140 dlinkAdd(anptr, &anptr->node, &watchTable[strhash(anptr->nick)]);
141 }
142 else
143 {
144 /* Is this client already on the watch-list? */
145 ptr = dlinkFind(&anptr->watched_by, client_p);
146 }
147
148 if (ptr == NULL)
149 {
150 /* No it isn't, so add it in the bucket and client addint it */
151 dlinkAdd(client_p, make_dlink_node(), &anptr->watched_by);
152 dlinkAdd(anptr, make_dlink_node(), &client_p->localClient->watches);
153 }
154 }
155
156 /*! \brief Removes a single entry from client_p's watch list
157 * \param nick Nick name to remove
158 * \param client_p Pointer to Client struct
159 */
160 void
161 watch_del_from_hash_table(const char *nick, struct Client *client_p)
162 {
163 struct Watch *anptr = NULL;
164 dlink_node *ptr = NULL;
165
166 if ((anptr = watch_find_hash(nick)) == NULL)
167 return; /* No header found for that nick. i.e. it's not being watched */
168
169 if ((ptr = dlinkFind(&anptr->watched_by, client_p)) == NULL)
170 return; /* This nick isn't being watched by client_p */
171
172 dlinkDelete(ptr, &anptr->watched_by);
173 free_dlink_node(ptr);
174
175 if ((ptr = dlinkFindDelete(&client_p->localClient->watches, anptr)))
176 free_dlink_node(ptr);
177
178 /* In case this header is now empty of notices, remove it */
179 if (anptr->watched_by.head == NULL)
180 {
181 assert(dlinkFind(&watchTable[strhash(anptr->nick)], anptr));
182 dlinkDelete(&anptr->node, &watchTable[strhash(anptr->nick)]);
183 mp_pool_release(anptr);
184 }
185 }
186
187 /*! \brief Removes all entries from client_p's watch list
188 * and deletes headers that are no longer being watched.
189 * \param client_p Pointer to Client struct
190 */
191 void
192 watch_del_watch_list(struct Client *client_p)
193 {
194 dlink_node *ptr = NULL, *ptr_next = NULL;
195 dlink_node *tmp = NULL;
196
197 DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->localClient->watches.head)
198 {
199 struct Watch *anptr = ptr->data;
200
201 assert(dlinkFind(&anptr->watched_by, client_p));
202
203 if ((tmp = dlinkFindDelete(&anptr->watched_by, client_p)))
204 free_dlink_node(tmp);
205
206 /* If this leaves a header without notifies, remove it. */
207 if (anptr->watched_by.head == NULL)
208 {
209 assert(dlinkFind(&watchTable[strhash(anptr->nick)], anptr));
210 dlinkDelete(&anptr->node, &watchTable[strhash(anptr->nick)]);
211
212 mp_pool_release(anptr);
213 }
214
215 dlinkDelete(ptr, &client_p->localClient->watches);
216 free_dlink_node(ptr);
217 }
218
219 assert(client_p->localClient->watches.head == NULL);
220 assert(client_p->localClient->watches.tail == NULL);
221 }

Properties

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