ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/src/whowas.c
(Generate patch)

Comparing ircd-hybrid/trunk/src/whowas.c (file contents):
Revision 4767 by michael, Sun Oct 19 18:02:20 2014 UTC vs.
Revision 7441 by michael, Thu Mar 10 20:21:20 2016 UTC

# Line 1 | Line 1
1   /*
2   *  ircd-hybrid: an advanced, lightweight Internet Relay Chat Daemon (ircd)
3   *
4 < *  Copyright (c) 1997-2014 ircd-hybrid development team
4 > *  Copyright (c) 1997-2016 ircd-hybrid development team
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 26 | Line 26
26  
27   #include "stdinc.h"
28   #include "list.h"
29 + #include "mempool.h"
30   #include "whowas.h"
31   #include "client.h"
32   #include "hash.h"
33   #include "irc_string.h"
34   #include "ircd.h"
35 + #include "send.h"
36 + #include "conf.h"
37  
38  
39 < static struct Whowas WHOWAS[NICKNAMEHISTORYLENGTH];
39 > static mp_pool_t *whowas_pool;
40 >
41 > static dlink_list whowas_list;  /*! Chain of struct Whowas pointers */
42   dlink_list WHOWASHASH[HASHSIZE];
43  
44  
45 + /*! \brief Initializes the whowas memory pool
46 + */
47   void
48   whowas_init(void)
49   {
50 <  for (unsigned int i = 0; i < NICKNAMEHISTORYLENGTH; ++i)
44 <    WHOWAS[i].hashv = -1;
50 >  whowas_pool = mp_pool_new(sizeof(struct Membership), MP_CHUNK_SIZE_WHOWAS);
51   }
52  
53 < void
54 < whowas_add_history(struct Client *client_p, const int online)
53 > /*! \brief Unlinks a Whowas struct from its associated lists.
54 > * \param whowas Pointer to Whowas struct to be unlinked
55 > */
56 > static struct Whowas *
57 > whowas_unlink(struct Whowas *whowas)
58   {
59 <  static unsigned int whowas_next = 0;
60 <  struct Whowas *const who = &WHOWAS[whowas_next];
59 >  if (!whowas)  /* Can be NULL. */
60 >    return NULL;
61  
62 <  assert(IsClient(client_p));
62 >  if (whowas->online)
63 >    dlinkDelete(&whowas->cnode, &whowas->online->whowas);
64 >
65 >  dlinkDelete(&whowas->tnode, &WHOWASHASH[whowas->hashv]);
66 >  dlinkDelete(&whowas->lnode, &whowas_list);
67  
68 <  if (++whowas_next == NICKNAMEHISTORYLENGTH)
69 <    whowas_next = 0;
68 >  return whowas;
69 > }
70 >
71 > /*! \brief Unlinks a Whowas struct from its associated lists
72 > *         and returns memory back to the pooling allocator.
73 > * \param whowas Pointer to Whowas struct to be unlinked and freed
74 > */
75 > static void
76 > whowas_free(struct Whowas *whowas)
77 > {
78 >  whowas_unlink(whowas);
79 >  mp_pool_release(whowas);
80 > }
81 >
82 > /*! \brief Returns a Whowas struct for further use. Either allocates
83 > *         a new one, or returns the oldest entry from the whowas_list
84 > *         if it ran over ConfigGeneral.whowas_history_length
85 > */
86 > static struct Whowas *
87 > whowas_make(void)
88 > {
89 >  struct Whowas *whowas;
90 >
91 >  if (dlink_list_length(&whowas_list) >= ConfigGeneral.whowas_history_length)
92 >    whowas = whowas_unlink(whowas_list.tail->data);  /* Re-use oldest item */
93 >  else
94 >    whowas = mp_pool_get(whowas_pool);
95 >
96 >  return whowas;
97 > }
98  
99 <  if (who->hashv != -1)
99 > /*! \brief Trims the whowas_list if necessary until there are no
100 > *         more than ConfigGeneral.whowas_history_length Whowas
101 > *         struct items.
102 > */
103 > void
104 > whowas_trim(void)
105 > {
106 >  while (dlink_list_length(&whowas_list) >= ConfigGeneral.whowas_history_length)
107    {
108 <    if (who->online)
109 <      dlinkDelete(&who->cnode, &who->online->whowas);
108 >    if (!whowas_list.tail->data)
109 >      return;  /* whowas_list is now empty. No more items can be freed. */
110  
111 <    dlinkDelete(&who->tnode, &WHOWASHASH[who->hashv]);
111 >    whowas_free(whowas_list.tail->data);
112    }
113 + }
114 +
115 + /*! \brief Adds the currently defined name of the client to history.
116 + *         Usually called before changing to a new name (nick).
117 + *         Client must be a fully registered user.
118 + * \param client_p pointer to Client struct to add
119 + * \param online   either 1 if it's a nick change or 0 on client exit
120 + */
121 + void
122 + whowas_add_history(struct Client *client_p, const int online)
123 + {
124 +  struct Whowas *whowas = whowas_make();
125  
126 <  who->hashv = strhash(client_p->name);
127 <  who->shide = IsHidden(client_p->servptr) != 0;
128 <  who->logoff = CurrentTime;
129 <
130 <  strlcpy(who->svid, client_p->svid, sizeof(who->svid));
131 <  strlcpy(who->name, client_p->name, sizeof(who->name));
132 <  strlcpy(who->username, client_p->username, sizeof(who->username));
133 <  strlcpy(who->hostname, client_p->host, sizeof(who->hostname));
134 <  strlcpy(who->realname, client_p->info, sizeof(who->realname));
135 <  strlcpy(who->servername, client_p->servptr->name, sizeof(who->servername));
126 >  if (!whowas)  /* Can be NULL. */
127 >    return;
128 >
129 >  assert(IsClient(client_p));
130 >
131 >  whowas->hashv = strhash(client_p->name);
132 >  whowas->shide = IsHidden(client_p->servptr) != 0;
133 >  whowas->logoff = CurrentTime;
134 >
135 >  strlcpy(whowas->account, client_p->account, sizeof(whowas->account));
136 >  strlcpy(whowas->name, client_p->name, sizeof(whowas->name));
137 >  strlcpy(whowas->username, client_p->username, sizeof(whowas->username));
138 >  strlcpy(whowas->hostname, client_p->host, sizeof(whowas->hostname));
139 >  strlcpy(whowas->sockhost, client_p->sockhost, sizeof(whowas->sockhost));
140 >  strlcpy(whowas->realname, client_p->info, sizeof(whowas->realname));
141 >  strlcpy(whowas->servername, client_p->servptr->name, sizeof(whowas->servername));
142  
143    if (online)
144    {
145 <    who->online = client_p;
146 <    dlinkAdd(who, &who->cnode, &client_p->whowas);
145 >    whowas->online = client_p;
146 >    dlinkAdd(whowas, &whowas->cnode, &client_p->whowas);
147    }
148    else
149 <    who->online = NULL;
149 >    whowas->online = NULL;
150  
151 <  dlinkAdd(who, &who->tnode, &WHOWASHASH[who->hashv]);
151 >  dlinkAdd(whowas, &whowas->tnode, &WHOWASHASH[whowas->hashv]);
152 >  dlinkAdd(whowas, &whowas->lnode, &whowas_list);
153   }
154  
155 + /*! \brief This must be called when the client structure is about to
156 + *         be released. History mechanism keeps pointers to client
157 + *         structures and it must know when they cease to exist.
158 + * \param client_p pointer to Client struct
159 + */
160   void
161   whowas_off_history(struct Client *client_p)
162   {
163 <  dlink_node *ptr = NULL, *ptr_next = NULL;
92 <
93 <  DLINK_FOREACH_SAFE(ptr, ptr_next, client_p->whowas.head)
163 >  while (client_p->whowas.head)
164    {
165 <    struct Whowas *temp = ptr->data;
165 >    struct Whowas *whowas = client_p->whowas.head->data;
166  
167 <    temp->online = NULL;
168 <    dlinkDelete(&temp->cnode, &client_p->whowas);
167 >    whowas->online = NULL;
168 >    dlinkDelete(&whowas->cnode, &client_p->whowas);
169    }
170   }
171  
172 + /*! \brief Returns the current client that was using the given
173 + *         nickname within the timelimit. Returns NULL, if no
174 + *         one found.
175 + * \param name      name of the nick
176 + * \param timelimit maximum age for a client since log-off
177 + */
178   struct Client *
179 < whowas_get_history(const char *nick, time_t timelimit)
179 > whowas_get_history(const char *name, uintmax_t timelimit)
180   {
181 <  dlink_node *ptr = NULL;
181 >  dlink_node *node = NULL;
182  
183    timelimit = CurrentTime - timelimit;
184  
185 <  DLINK_FOREACH(ptr, WHOWASHASH[strhash(nick)].head)
185 >  DLINK_FOREACH(node, WHOWASHASH[strhash(name)].head)
186    {
187 <    struct Whowas *temp = ptr->data;
187 >    struct Whowas *whowas = node->data;
188  
189 <    if (temp->logoff < timelimit)
189 >    if (whowas->logoff < timelimit)
190        continue;
191 <    if (irccmp(nick, temp->name))
191 >    if (irccmp(name, whowas->name))
192        continue;
193 <    return temp->online;
193 >    return whowas->online;
194    }
195  
196    return NULL;
197   }
198  
199 + /*! \brief For debugging. Counts allocated structures stored in whowas_list
200 + */
201   void
202 < whowas_count_memory(unsigned int *const count, uint64_t *const bytes)
202 > whowas_count_memory(unsigned int *const count, size_t *const bytes)
203   {
204 <  const struct Whowas *tmp = &WHOWAS[0];
205 <
128 <  for (unsigned int i = 0; i < NICKNAMEHISTORYLENGTH; ++i, ++tmp)
129 <  {
130 <    if (tmp->hashv != -1)
131 <    {
132 <      (*count)++;
133 <      (*bytes) += sizeof(struct Whowas);
134 <    }
135 <  }
204 >  (*count) = dlink_list_length(&whowas_list);
205 >  (*bytes) = dlink_list_length(&whowas_list) * sizeof(struct Whowas);
206   }

Diff Legend

Removed lines
+ Added lines
< Changed lines (old)
> Changed lines (new)