1 /*
2 SMS Server Tools 3
3 Copyright (C) 2006- Keijo Kasvi
4 http://smstools3.kekekasvi.com/
5
6 Based on SMS Server Tools 2, http://stefanfrings.de/smstools/
7 SMS Server Tools version 2 and below are Copyright (C) Stefan Frings.
8
9 This program is free software unless you got it under another license directly
10 from the author. You can redistribute it and/or modify it under the terms of
11 the GNU General Public License as published by the Free Software Foundation.
12 Either version 2 of the License, or (at your option) any later version.
13 */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <limits.h>
20 #include "alarm.h"
21 #include "smsd_cfg.h"
22 #include "stats.h"
23 #include <syslog.h>
24 #include "logging.h"
25 #include "modeminit.h"
26 #include "extras.h"
27 #include <errno.h>
28 #ifndef NOSTATS
29 #include <mm.h>
30 #endif
31
32 char newstatus[NUMBER_OF_MODEMS +1] = {0};
33 char oldstatus[NUMBER_OF_MODEMS +1] = {0};
34
35 char *statistics_current_version = "VERSION 3.1.5-1";
36
initstats()37 void initstats()
38 {
39 int i;
40
41 // if the mm Library is not available the statistic funktion does not work.
42 // Use unshared memory instead disabling all statistc related functions.
43 // This is much easier to program.
44 #ifndef NOSTATS
45 // 3.1.5: get rid of tempnam:
46 //MM_create(DEVICES*sizeof(_stats),tempnam(0,0));
47
48 char filename[PATH_MAX];
49 size_t size;
50
51 // mm library also defaults to /tmp directory with pid,
52 // .sem will be added to name inside mm.
53 sprintf(filename, MM_CORE_FNAME, (int)getpid());
54
55 // 3.1.18: Fix: Each allocation needs 16 bytes more space. If number of modems was set
56 // to 124 or more, there was not enough shared memory available.
57 //if (MM_create(NUMBER_OF_MODEMS *sizeof(_stats) +SIZE_SHARED_BUFFER, filename) == 0)
58 size = NUMBER_OF_MODEMS * (sizeof(_stats) + 16) + SIZE_SHARED_BUFFER + 16;
59 if (MM_create(size, filename) == 0)
60 {
61 writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot create shared memory for statistics."));
62 alarm_handler0(LOG_ERR, tb);
63 exit(EXIT_FAILURE);
64 }
65 #endif
66
67 for (i = 0; i < NUMBER_OF_MODEMS; i++)
68 {
69 #ifndef NOSTATS
70 if ((statistics[i]=(_stats*)MM_malloc(sizeof(_stats))))
71 #else
72 if ((statistics[i]=(_stats*)malloc(sizeof(_stats))))
73 #endif
74 {
75 statistics[i]->succeeded_counter = 0;
76 statistics[i]->failed_counter = 0;
77 statistics[i]->received_counter = 0;
78 statistics[i]->multiple_failed_counter = 0;
79 statistics[i]->status = '-';
80 statistics[i]->usage_s = 0;
81 statistics[i]->usage_r = 0;
82 statistics[i]->message_counter = 0;
83 statistics[i]->last_init = 0;
84 statistics[i]->ssi = -1;
85 statistics[i]->ber = -1;
86 }
87 else
88 {
89 writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot reserve memory for statistics."));
90 alarm_handler0(LOG_ERR, tb);
91 #ifndef NOSTATS
92 MM_destroy();
93 #endif
94 exit(EXIT_FAILURE);
95 }
96 }
97
98 #ifndef NOSTATS
99 if ((shared_buffer = (char *)MM_malloc(SIZE_SHARED_BUFFER)))
100 #else
101 if ((shared_buffer = (char *)malloc(SIZE_SHARED_BUFFER)))
102 #endif
103 *shared_buffer = 0;
104 else
105 {
106 writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot reserve memory for shared buffer."));
107 alarm_handler0(LOG_ERR, tb);
108 #ifndef NOSTATS
109 MM_destroy();
110 #endif
111 exit(EXIT_FAILURE);
112 }
113
114 rejected_counter=0;
115 start_time=time(0);
116 last_stats=time(0);
117 }
118
resetstats()119 void resetstats()
120 {
121 int i;
122
123 for (i = 0; i < NUMBER_OF_MODEMS; i++)
124 {
125 statistics[i]->succeeded_counter = 0;
126 statistics[i]->failed_counter = 0;
127 statistics[i]->received_counter = 0;
128 statistics[i]->multiple_failed_counter = 0;
129 statistics[i]->status = '-';
130 statistics[i]->usage_s = 0;
131 statistics[i]->usage_r = 0;
132
133 // message_counter remains untouched.
134
135 // last_init and signal quality remains untouched.
136
137 }
138
139 rejected_counter = 0;
140 start_time = time(0);
141 last_stats = time(0);
142 }
143
savestats()144 void savestats()
145 {
146 char filename[PATH_MAX];
147 FILE *fp;
148 int i;
149 time_t now;
150
151 if (d_stats[0] && stats_interval)
152 {
153 now = time(0);
154 sprintf(filename, "%s/stats.tmp", d_stats);
155 if ((fp = fopen(filename, "w")))
156 {
157 fwrite(statistics_current_version, strlen(statistics_current_version) +1, 1, fp);
158
159 fwrite(&now, sizeof(now), 1, fp);
160 fwrite(&start_time, sizeof(start_time), 1, fp);
161 for (i = 0; i < NUMBER_OF_MODEMS; i++)
162 fwrite(statistics[i], sizeof(_stats), 1, fp);
163 fclose(fp);
164 }
165 else
166 {
167 writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot write tmp file for statistics. %s %s", filename, strerror(errno)));
168 alarm_handler0(LOG_ERR, tb);
169 }
170 }
171 }
172
loadstats()173 void loadstats()
174 {
175 char filename[PATH_MAX];
176 FILE *fp;
177 int i;
178 time_t saved_time;
179 char tmp[81];
180
181 if (d_stats[0] && stats_interval)
182 {
183 sprintf(filename, "%s/stats.tmp", d_stats);
184 if ((fp = fopen(filename,"r")))
185 {
186 fread(tmp, strlen(statistics_current_version) +1, 1, fp);
187
188 if (strncmp(statistics_current_version, tmp, strlen(statistics_current_version)))
189 writelogfile0(LOG_ERR, 0, tb_sprintf("Not loading statistics tmp file because version has changed."));
190 else
191 {
192 fread(&saved_time, sizeof(time_t), 1, fp);
193 fread(&start_time, sizeof(time_t), 1, fp);
194 start_time = time(0) -(saved_time -start_time);
195
196 for (i = 0; i < NUMBER_OF_MODEMS; i++)
197 {
198 fread(statistics[i], sizeof(_stats), 1, fp);
199
200 statistics[i]->status = '-';
201 statistics[i]->last_init = 0;
202 statistics[i]->ssi = -1;
203 statistics[i]->ber = -1;
204 }
205 }
206 fclose(fp);
207 }
208 }
209 }
210
print_status()211 void print_status()
212 {
213 #ifndef NOSTATS
214 int j;
215
216 if (printstatus)
217 {
218 strcpy(oldstatus,newstatus);
219 for (j = 0; j < NUMBER_OF_MODEMS; j++)
220 newstatus[j]=statistics[j]->status;
221 newstatus[NUMBER_OF_MODEMS] = 0;
222 if (strcmp(oldstatus,newstatus))
223 {
224 printf("%s\n",newstatus);
225 }
226 }
227 #endif
228 }
229
checkwritestats()230 void checkwritestats()
231 {
232 #ifndef NOSTATS
233 time_t now;
234 time_t next_time;
235 char filename[PATH_MAX];
236 char s[20];
237 FILE* datei;
238 int i;
239 int sum_counter;
240
241 if (d_stats[0] && stats_interval)
242 {
243 next_time=last_stats+stats_interval;
244 next_time=stats_interval*(next_time/stats_interval); // round value
245 now=time(0);
246 if (now>=next_time) // reached timepoint of next stats file?
247 {
248 // Check if there was activity if user does not want zero-files
249 if (stats_no_zeroes)
250 {
251 sum_counter=rejected_counter;
252 for (i = 0; i < NUMBER_OF_MODEMS; i++)
253 {
254 if (devices[i].name[0])
255 {
256 sum_counter+=statistics[i]->succeeded_counter;
257 sum_counter+=statistics[i]->failed_counter;
258 sum_counter+=statistics[i]->received_counter;
259 sum_counter+=statistics[i]->multiple_failed_counter;
260 }
261 }
262 if (sum_counter==0)
263 {
264 resetstats();
265 last_stats=now;
266 return;
267 }
268 }
269
270 last_stats=time(0);
271 // %Y used instead of %y to avoid compiler warning message in some environments.
272 strftime(s,sizeof(s),"%Y%m%d.%H%M%S",localtime(&next_time));
273 strcpyo(s, s +2);
274 syslog(LOG_INFO,"Writing stats file %s",s);
275 strcpy(filename,d_stats);
276 strcat(filename,"/");
277 strcat(filename,s);
278 datei=fopen(filename,"w");
279 if (datei)
280 {
281 fprintf(datei,"runtime,rejected\n");
282
283 //fprintf(datei,"%li,%i\n\n", now -start_time, rejected_counter);
284 fprintf(datei, "%lld,%i\n\n", (long long int)now -start_time, rejected_counter);
285
286 fprintf(datei,"name,succeeded,failed,received,multiple_failed,usage_s,usage_r\n");
287 for (i = 0; i < NUMBER_OF_MODEMS; i++)
288 {
289 if (devices[i].name[0])
290 fprintf(datei,"%s,%i,%i,%i,%i,%i,%i\n",
291 devices[i].name,
292 statistics[i]->succeeded_counter,
293 statistics[i]->failed_counter,
294 statistics[i]->received_counter,
295 statistics[i]->multiple_failed_counter,
296 statistics[i]->usage_s,
297 statistics[i]->usage_r);
298 }
299 fclose(datei);
300 resetstats();
301 last_stats=now;
302 }
303 else
304 {
305 writelogfile0(LOG_ERR, 0, tb_sprintf("Cannot write statistic file. %s %s",filename,strerror(errno)));
306 alarm_handler0(LOG_ERR, tb);
307 }
308 }
309 }
310 #endif
311 }
312
313 // 3.1.1:
update_message_counter(int messages,char * modemname)314 void update_message_counter(int messages, char *modemname)
315 {
316 char filename[PATH_MAX];
317 FILE *fp;
318 char temp[256];
319 int counter = 0;
320 char *p;
321
322 if (*d_stats)
323 {
324 sprintf(filename, "%s/%s.counter", d_stats, modemname);
325
326 if ((fp = fopen(filename, "r")))
327 {
328 if (fgets(temp, sizeof(temp), fp))
329 {
330 if (!(p = strchr(temp, ':')))
331 p = temp;
332 else
333 p++;
334 counter = atoi(p);
335 }
336 fclose(fp);
337 }
338
339 // 3.1.7: always create a file
340
341 counter += messages;
342
343 if ((fp = fopen(filename, "w")))
344 {
345 fprintf(fp, "%s: %i\n", modemname, counter);
346 fclose(fp);
347 }
348
349 STATISTICS->message_counter = counter;
350 }
351 }
352
353 // 3.1.5:
write_status()354 void write_status()
355 {
356 #ifndef NOSTATS
357 int i;
358 char fname_tmp[PATH_MAX];
359 char fname[PATH_MAX];
360 FILE *fp;
361 char *status;
362 char buffer[256];
363 time_t t;
364 static size_t longest_modemname = 0;
365 int include_counters;
366
367 if (!printstatus && d_stats[0])
368 {
369 strcpy(oldstatus, newstatus);
370 for (i = 0; i < NUMBER_OF_MODEMS; i++)
371 newstatus[i] = statistics[i]->status;
372 newstatus[NUMBER_OF_MODEMS] = 0;
373
374 if (strcmp(oldstatus, newstatus))
375 {
376 sprintf(fname_tmp, "%s/status.tmp", d_stats);
377 if ((fp = fopen(fname_tmp, "w")))
378 {
379 if (!longest_modemname)
380 {
381 for (i = 0; i < NUMBER_OF_MODEMS; i++)
382 if (devices[i].name[0])
383 if (strlen(devices[i].name) > longest_modemname)
384 longest_modemname = strlen(devices[i].name);
385
386 if (status_include_uptime)
387 if (longest_modemname < 5) // "Start"
388 longest_modemname = 5;
389 }
390
391 t = time(0);
392 strftime(buffer, sizeof(buffer), datetime_format, localtime(&t));
393 fprintf(fp, "Status:%s\t%s,\t%s\n", (longest_modemname >= 7)? "\t" : "", buffer, newstatus);
394
395 for (i = 0; i < NUMBER_OF_MODEMS; i++)
396 {
397 if (devices[i].name[0] == 0)
398 continue;
399 switch (newstatus[i])
400 {
401 case 's':
402 status = "Sending";
403 break;
404
405 case 'r':
406 status = "Receiving";
407 break;
408
409 case 'i':
410 status = "Idle";
411 break;
412
413 case 'b':
414 status = "Blocked";
415 break;
416
417 case 't':
418 status = "Trouble";
419 break;
420
421 default:
422 status = "Unknown";
423 }
424
425 if (statistics[i]->last_init)
426 strftime(buffer, sizeof(buffer), datetime_format, localtime(&(statistics[i]->last_init)));
427 else
428 strcpy(buffer, "-");
429
430 fprintf(fp, "%s:%s\t%s,\t%s", devices[i].name, (strlen(devices[i].name) < 7 && longest_modemname >= 7)? "\t" : "", buffer, status);
431
432 include_counters = 0;
433 if (devices[i].status_include_counters == 1 ||
434 (devices[i].status_include_counters == -1 && status_include_counters))
435 include_counters = 1;
436
437 if (include_counters || statistics[i]->ssi >= 0)
438 fprintf(fp, ",%s", (strlen(status) < 7)? "\t" : "");
439
440 if (include_counters)
441 fprintf(fp, "\t%i,\t%i,\t%i", statistics[i]->message_counter, statistics[i]->failed_counter, statistics[i]->received_counter);
442
443 if (statistics[i]->ssi >= 0)
444 {
445 if (include_counters)
446 fprintf(fp, ",");
447
448 explain_csq_buffer(buffer, 1, statistics[i]->ssi, statistics[i]->ber, devices[i].signal_quality_ber_ignore);
449 fprintf(fp, "\t%s", buffer);
450 }
451
452 fprintf(fp, "\n");
453 }
454
455 // 3.1.16beta:
456 if (status_include_uptime)
457 {
458 char upstr[64];
459
460 strftime(buffer, sizeof(buffer), datetime_format, localtime(&process_start_time));
461 make_uptime_string(upstr, sizeof(upstr), t - process_start_time);
462 fprintf(fp, "\nStart:%s\t%s,\tup %s\n", (longest_modemname >= 7)? "\t" : "", buffer, upstr);
463 }
464
465 fclose(fp);
466
467 sprintf(fname, "%s/status", d_stats);
468 rename(fname_tmp, fname);
469 }
470 }
471 }
472 #endif
473 }
474