Docs/ModUserOnline: mod_useronline.4.c

File mod_useronline.4.c, 8.1 kB (added by Wojjie, 3 weeks ago)

mod_useronline (1.5.x)

Line 
1 #include <ctype.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "base.h"
6 #include "buffer.h"
7
8 #include "plugin.h"
9 #include "inet_ntop_cache.h"
10 #include "status_counter.h"
11
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 typedef struct {
17         size_t  online_age;
18         size_t  active_age;
19
20         size_t  max_ips;
21         size_t  id;
22         int     enable;
23         data_integer **status_counters;
24 } plugin_config;
25
26 typedef struct {
27         unsigned int ipl;
28         int hits;
29         time_t last;
30 } user_data;
31
32 typedef struct {
33         PLUGIN_DATA;
34         plugin_config **config_storage;
35        
36         plugin_config *conf;
37         user_data **ip_data;
38 } plugin_data;
39
40
41 INIT_FUNC(mod_useronline_init) {
42         plugin_data *p;
43        
44         p = calloc(1, sizeof(*p));
45         return p;
46 }
47
48 #define NUM_STATUS_NAMES 6
49 FREE_FUNC(mod_useronline_free) {
50         plugin_data *p = p_d;
51        
52         UNUSED(srv);
53
54         if (!p) return HANDLER_GO_ON;
55        
56         if (p->config_storage) {
57                 size_t i;
58                 for (i = 0; i < srv->config_context->used; i++) {
59                         plugin_config *s = p->config_storage[i];
60                
61                         free(p->ip_data[i]);
62                         if (s->status_counters) {
63                                 free(s->status_counters);
64                         }
65                         free(s);
66                 }
67                 free(p->config_storage);
68                 free(p->ip_data);
69         }
70        
71         free(p);
72        
73         return HANDLER_GO_ON;
74 }
75
76 SETDEFAULTS_FUNC(mod_useronline_set_defaults) {
77         plugin_data *p = p_d;
78         size_t i = 0, j=0;
79        
80         config_values_t cv[] = {
81                 { "useronline.online-age",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
82                 { "useronline.active-age",      NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
83                 { "useronline.max-ips",         NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
84                 { "useronline.enable",          NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
85                 { "useronline.status-name",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
86                
87                 { NULL,                        NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
88         };
89        
90         if (!p) return HANDLER_ERROR;
91        
92         /* 0 */
93         p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
94         p->ip_data = calloc(1, srv->config_context->used * sizeof(user_data *));
95        
96         for (i = 0; i < srv->config_context->used; i++) {
97                 plugin_config *s;
98                 buffer *status_name;
99                 buffer **keyname;
100
101                 s = calloc(1, sizeof(plugin_config));
102                 s->online_age   = 300;
103                 s->active_age   = 0;
104                 s->max_ips      = 1024;
105                 s->id           = i;
106                 s->enable       = 0;
107                 status_name=buffer_init();             
108                
109                 cv[0].destination = &(s->online_age);
110                 cv[1].destination = &(s->active_age);
111                 cv[2].destination = &(s->max_ips);
112                 cv[3].destination = &(s->enable);
113                 cv[4].destination = status_name;
114                
115                 p->config_storage[i] = s;
116        
117                 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
118                         return HANDLER_ERROR;
119                 }
120
121                 if (s->enable) {
122                         if (s->active_age==0) s->active_age = s->online_age/3;
123                                
124                         p->ip_data[i] = calloc(s->max_ips, sizeof(user_data));
125                         p->ip_data[i][0].hits=-1;
126                 }
127                 /*not used? free the memory*/
128                 if (status_name->used==0 || !s->enable) {
129                         buffer_free(status_name);
130                 } else {
131                         keyname = calloc(NUM_STATUS_NAMES, sizeof(buffer*));
132                         s->status_counters = calloc(NUM_STATUS_NAMES, sizeof(data_integer*));
133                         for (j=0; j<NUM_STATUS_NAMES; j++) {
134                                 keyname[j] = buffer_init_string("useronline.");
135                                 buffer_append_string    (keyname[j],    status_name->ptr);
136                                 buffer_append_string    (keyname[j],    ".");
137                         }
138                         buffer_free(status_name);
139                
140                         buffer_append_string    (keyname[0], "id");
141                         buffer_append_string    (keyname[1], "users-online");
142                         buffer_append_string    (keyname[2], "users-active");
143                         buffer_append_string    (keyname[3], "online-age");
144                         buffer_append_string    (keyname[4], "active-age");
145                         buffer_append_string    (keyname[5], "max-ips");
146                         for(j=0; j<NUM_STATUS_NAMES; j++) {
147                                 s->status_counters[j] = status_counter_get_counter( CONST_BUF_LEN(keyname[j]) );
148                                 buffer_free(keyname[j]);
149                         }
150
151                         COUNTER_SET( s->status_counters[0], i );
152                         COUNTER_SET( s->status_counters[3], s->online_age );
153                         COUNTER_SET( s->status_counters[4], s->active_age );
154                         COUNTER_SET( s->status_counters[5], s->max_ips );
155
156                         free(keyname);
157                 }
158         }
159        
160         return HANDLER_GO_ON;
161 }
162 #undef NUM_STATUS_NAMES
163
164 #define PATCH() \
165         p->conf = s;
166 static int mod_useronline_patch_connection(server *srv, connection *con, plugin_data *p) {
167         size_t i;
168         plugin_config *s = p->config_storage[0];
169
170         PATCH();
171        
172         /* skip the first, the global context */
173         for (i = 1; i < srv->config_context->used; i++) {
174                 data_config *dc = (data_config *)srv->config_context->data[i];
175                 s = p->config_storage[i];
176                
177                 /* condition didn't match */
178                 if (!config_check_cond(srv, con, dc)) continue;
179                
180                 PATCH();
181         }
182        
183         return 0;
184 }
185 #undef PATCH
186
187 static void mod_useronline_add_env_int(array  *env, const char *key, int value) {
188         data_string *ds;
189         if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
190                 ds = data_string_init();
191         }
192         buffer_copy_string(ds->key, key);
193         buffer_copy_long(ds->value, value);
194         array_insert_unique(env, (data_unset *)ds);
195 }
196
197 URIHANDLER_FUNC(mod_useronline_uri_handler) {
198         plugin_data *p = p_d;
199         size_t j;
200         plugin_config *s;
201         user_data *ipd;
202         unsigned int ipl;
203         time_t time_threshold;
204         time_t active_threshold;
205        
206         size_t user_count       = 0;
207         size_t user_active      = 0;
208         int free_slot           = -1;
209         size_t last_item        = 0;
210         int foundat             = -1;
211         time_t current_time     = srv->cur_ts;
212
213         mod_useronline_patch_connection(srv, con, p);
214        
215         if (!p->conf->enable) return HANDLER_GO_ON;
216
217         s               = p->conf;
218         ipd             = p->ip_data[s->id];
219         ipl             = inet_addr(inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
220         time_threshold  = current_time - (s->online_age);
221         active_threshold= current_time - (s->active_age);
222                
223         for (j=0; j<s->max_ips; j++) {
224                 if (ipd[j].ipl==0) {
225                         /*empty entry, mark it if first free slot*/
226                         if (free_slot==-1) free_slot=j;
227                         if (ipd[j].hits==-1) {
228                                 /* end found */
229                                 j=s->max_ips;
230                         }
231                 } else if (ipd[j].ipl==ipl) {
232                         /*found a previous entry...*/
233                         foundat=j;
234                         ipd[j].hits++;
235                         ipd[j].last=current_time;
236                 } else if (ipd[j].last < time_threshold) {
237                         /*expired ip, mark it if first free slot*/
238                         ipd[j].ipl=0;
239                         if (free_slot==-1) free_slot=j;
240                 }
241                 if (ipd[j].ipl>0) {
242                         /*count user/ip*/
243                         if (ipd[j].last >= active_threshold) user_active++;
244                         user_count++;
245                         last_item=j;
246                 }
247         }
248                                
249         if (foundat==-1) {
250                 /*not found, add new*/
251                 if (free_slot!=-1) {
252                         ipd[free_slot].ipl=ipl;
253                         ipd[free_slot].last=current_time;
254                         ipd[free_slot].hits=1;
255                         foundat=free_slot;
256                         if (free_slot>(int)last_item) last_item=free_slot;
257                        
258                         user_active++;
259                         user_count++;
260                 }
261         }
262                                
263         /*reduce amount of elements to scan through (mark as end, hits=-1)*/
264         if (last_item+1 < s->max_ips) {
265                 ipd[last_item+1].ipl=0;
266                 ipd[last_item+1].hits=-1;
267         }
268
269         /*set environment variables*/
270
271         /*users online currently*/
272         mod_useronline_add_env_int(con->environment, "users_online", user_count);
273         /*users active currently*/
274         mod_useronline_add_env_int(con->environment, "users_active", user_active);
275         /*hits made by current user*/
276         mod_useronline_add_env_int(con->environment, "user_hits", ipd[foundat].hits);
277         /*max age setting for current*/
278         mod_useronline_add_env_int(con->environment, "users_online_age", s->online_age);
279         /*max active age setting for current*/
280         mod_useronline_add_env_int(con->environment, "users_active_age", s->active_age);
281         /*max ips setting for current*/
282         mod_useronline_add_env_int(con->environment, "users_online_max_ips", s->max_ips);
283         /*current id for current*/
284         mod_useronline_add_env_int(con->environment, "users_online_id", s->id);
285        
286         if (s->status_counters) {
287                 /*users online currently*/
288                 COUNTER_SET( s->status_counters[1], user_count );
289                 /*users active currently*/
290                 COUNTER_SET( s->status_counters[2], user_active );
291         }
292         return HANDLER_GO_ON;
293 }
294
295 int mod_useronline_plugin_init(plugin *p) {
296         p->version     = LIGHTTPD_VERSION_ID;
297         p->name        = buffer_init_string("useronline");
298        
299         p->init        = mod_useronline_init;
300         p->handle_uri_clean = mod_useronline_uri_handler;
301         p->set_defaults   = mod_useronline_set_defaults;
302         p->cleanup        = mod_useronline_free;
303        
304         p->data        = NULL;
305        
306         return 0;
307 }