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