Docs/ModUserOnline: mod_useronline.3.c

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