1/* 2 3 rstats 4 Copyright (C) 2006-2009 Jonathan Zarate 5 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License 9 as published by the Free Software Foundation; either version 2 10 of the License, or (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17*/ 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <unistd.h> 23#include <signal.h> 24#include <time.h> 25#include <sys/types.h> 26#include <sys/sysinfo.h> 27#include <sys/stat.h> 28#include <stdint.h> 29#include <syslog.h> 30#include <ctype.h> 31 32#include <bcmnvram.h> 33#include <shutils.h> 34 35//#define DEBUG_NOISY 36//#define DEBUG_STIME 37 38#include <shared.h> 39 40#ifdef RTCONFIG_ISP_METER 41 #include <rtstate.h> 42#endif 43 44#ifdef RTCONFIG_QTN 45#include "web-qtn.h" 46#endif 47 48//#define DEBUG 49#define K 1024 50#define M (1024 * 1024) 51#define G (1024 * 1024 * 1024) 52 53#define SMIN 60 54#define SHOUR (60 * 60) 55#define SDAY (60 * 60 * 24) 56#define Y2K 946684800UL 57 58#define INTERVAL 30 59#if defined(RTCONFIG_WANPORT2) 60#define MAX_BW 2000 61#else 62#define MAX_BW 1000 63#endif 64 65#ifdef RTCONFIG_ISP_METER 66 #define MTD_WRITE_INTERVEL 60 67#endif 68 69#define MAX_NSPEED ((24 * SHOUR) / INTERVAL) 70#define MAX_NDAILY 62 71#define MAX_NMONTHLY 25 72/* INTERNET: 2 73 * WIRED: 1 74 * BRIDGE: 1 75 * WIFI_2G: 4 76 * WIFI_5G: 4 x number of 5g bands 77 */ 78#define MAX_SPEED_IF 25 79 80#define MAX_ROLLOVER (MAX_BW * INTERVAL / 8ULL * M) 81 82#define MAX_COUNTER 2 83#define RX 0 84#define TX 1 85 86#define DAILY 0 87#define MONTHLY 1 88 89#define ID_V0 0x30305352 90#define ID_V1 0x31305352 91#define CURRENT_ID ID_V1 92 93#define HI_BACK 5 94 95#define RA_OFFSET_ISP_METER 0x4FF00 96 97enum if_id { 98 IFID_INTERNET = 0, /* INTERNET */ 99 IFID_INTERNET1, /* INTERNET1 */ 100 IFID_WIRED, /* WIRED */ 101 IFID_BRIDGE, /* BRIDGE */ 102 IFID_WIRELESS0, /* WIRELESS0 */ 103 IFID_WIRELESS0_1, /* WIRELESS0.1 */ 104 IFID_WIRELESS0_2, /* WIRELESS0.2 */ 105 IFID_WIRELESS0_3, /* WIRELESS0.3 */ 106 IFID_WIRELESS1, /* WIRELESS1 */ 107 IFID_WIRELESS1_1, /* WIRELESS1.1 */ 108 IFID_WIRELESS1_2, /* WIRELESS1.2 */ 109 IFID_WIRELESS1_3, /* WIRELESS1.3 */ 110 IFID_WIRELESS2, /* WIRELESS2 */ 111 IFID_WIRELESS2_1, /* WIRELESS2.1 */ 112 IFID_WIRELESS2_2, /* WIRELESS2.2 */ 113 IFID_WIRELESS2_3, /* WIRELESS2.3 */ 114 115 IFID_MAX 116}; 117 118typedef struct { 119 uint32_t xtime; 120 uint64_t counter[MAX_COUNTER]; 121} data_t; 122 123typedef struct { 124 uint32_t id; 125 126 data_t daily[MAX_NDAILY]; 127 int dailyp; 128 129 data_t monthly[MAX_NMONTHLY]; 130 int monthlyp; 131} history_t; 132 133typedef struct { 134 uint32_t id; 135 136 data_t daily[62]; 137 int dailyp; 138 139 data_t monthly[12]; 140 int monthlyp; 141} history_v0_t; 142 143typedef struct { 144 char ifname[12]; 145 long utime; 146 unsigned long long speed[MAX_NSPEED][MAX_COUNTER]; 147 unsigned long long last[MAX_COUNTER]; 148 int tail; 149 int sync; 150} speed_t; 151 152history_t history; 153speed_t speed[MAX_SPEED_IF]; 154int speed_count; 155long save_utime; 156char save_path[96]; 157long current_uptime; 158 159volatile int gothup = 0; 160volatile int gotuser = 0; 161volatile int gotterm = 0; 162 163const char history_fn[] = "/var/lib/misc/rstats-history"; 164const char speed_fn[] = "/var/lib/misc/rstats-speed"; 165const char uncomp_fn[] = "/var/tmp/rstats-uncomp"; 166const char source_fn[] = "/var/lib/misc/rstats-source"; 167 168#ifdef RTCONFIG_ISP_METER 169#define ISP_METER_FILE "/jffs/isp_meter" 170int isp_limit, isp_limit_time; 171unsigned long last_day_rx, last_day_tx, last_month_rx, last_month_tx; 172unsigned long today_rx, today_tx, month_rx, month_tx; 173unsigned long reset_base_day_rx, reset_base_day_tx, reset_base_month_rx, reset_base_month_tx; 174long cur_conn_time, last_connect_time, total_connect_time, reset_base_time; 175 176void reset_traffic_meter_counter(){ 177 FILE *fp; 178 last_day_rx = 0; 179 last_day_tx = 0; 180 last_month_rx = 0; 181 last_month_tx = 0; 182 today_rx = 0; 183 today_tx = 0; 184 month_rx = 0; 185 month_tx = 0; 186 reset_base_day_rx = (history.daily[history.dailyp].counter[0]/K); 187 reset_base_day_tx = (history.daily[history.dailyp].counter[1]/K); 188 reset_base_month_rx = (history.monthly[history.monthlyp].counter[0]/K); 189 reset_base_month_tx = (history.monthly[history.monthlyp].counter[1]/K); 190 nvram_set("isp_day_tx", "0"); 191 nvram_set("isp_day_rx", "0"); 192 nvram_set("isp_month_tx", "0"); 193 nvram_set("isp_month_rx", "0"); 194 isp_limit = nvram_get_int("isp_limit"); 195 isp_limit_time = nvram_get_int("isp_limit_time"); 196 197 reset_base_time = cur_conn_time; 198 last_connect_time = 0; 199 total_connect_time = 0; 200 201 set_meter_file("isp_meter:0,0,0,end"); 202 203 if(!nvram_match("isp_meter", "disable") 204 && !(nvram_match("wan0_state_t", "2") && nvram_match("wan0_auxstate_t", "0")) ) { 205 notify_rc_and_wait("isp_meter up"); 206 } 207} 208 209void get_meter_file(char *meter_buf) 210{ 211#ifdef CONFIG_BCMWL5 212 FILE *fp; 213 if (fp=fopen(ISP_METER_FILE, "r")) { 214 fgets(meter_buf, sizeof(meter_buf), fp); 215 fclose(fp); 216 } 217#else 218 FRead(meter_buf, RA_OFFSET_ISP_METER, 64); 219#endif 220 _dprintf("meter_buf: %s\n", meter_buf); 221 return; 222} 223 224int set_meter_file(char *meter_buf) 225{ 226 if(meter_buf == NULL) 227 return 0; 228#ifdef CONFIG_BCMWL5 229 FILE *fp; 230 if (fp=fopen(ISP_METER_FILE, "w")) { 231 fprintf(fp, "%s", meter_buf); 232 fclose(fp); 233 } 234#else 235 FWrite(meter_buf, RA_OFFSET_ISP_METER, sizeof(meter_buf)); 236#endif 237 return 1; 238} 239#endif 240 241static int get_stime(void) 242{ 243#ifdef DEBUG_STIME 244 return 90; 245#else 246 int t; 247 t = nvram_get_int("rstats_stime"); 248 if (t < 1) t = 1; 249 else if (t > 8760) t = 8760; 250 return t * SHOUR; 251#endif 252} 253 254static int comp(const char *path, void *buffer, int size) 255{ 256 char s[256]; 257 258 if (f_write(path, buffer, size, 0, 0) != size) return 0; 259 260 sprintf(s, "%s.gz", path); 261 unlink(s); 262 263 sprintf(s, "gzip %s", path); 264 return system(s) == 0; 265} 266 267static void save(int quick) 268{ 269 int i; 270 char *bi, *bo; 271 int n; 272 int b; 273 char hgz[256]; 274 char tmp[256]; 275 char bak[256]; 276 char bkp[256]; 277 time_t now; 278 struct tm *tms; 279 static int lastbak = -1; 280 281 //_dprintf("%s: quick=%d\n", __FUNCTION__, quick); 282 283 f_write("/var/lib/misc/rstats-stime", &save_utime, sizeof(save_utime), 0, 0); 284 285 comp(speed_fn, speed, sizeof(speed[0]) * speed_count); 286 287/* 288 if ((now = time(0)) < Y2K) { 289 _dprintf("%s: time not set\n", __FUNCTION__); 290 return; 291 } 292*/ 293 294 comp(history_fn, &history, sizeof(history)); 295 296 //_dprintf("%s: write source=%s\n", __FUNCTION__, save_path); 297 f_write_string(source_fn, save_path, 0, 0); 298 299 if (quick) { 300 return; 301 } 302 303 sprintf(hgz, "%s.gz", history_fn); 304 305 if (strcmp(save_path, "*nvram") == 0) { 306 if (!wait_action_idle(10)) { 307 _dprintf("%s: busy, not saving\n", __FUNCTION__); 308 return; 309 } 310 311 if ((n = f_read_alloc(hgz, &bi, 20 * 1024)) > 0) { 312 if ((bo = malloc(base64_encoded_len(n) + 1)) != NULL) { 313 n = base64_encode(bi, bo, n); 314 bo[n] = 0; 315 nvram_set("rstats_data", bo); 316 if (!nvram_match("debug_nocommit", "1")) nvram_commit(); 317 318 _dprintf("%s: nvram commit\n", __FUNCTION__); 319 320 free(bo); 321 } 322 } 323 free(bi); 324 } 325 else if (save_path[0] != 0) { 326 strcpy(tmp, save_path); 327 strcat(tmp, ".tmp"); 328 329 for (i = 15; i > 0; --i) { 330 if (!wait_action_idle(10)) { 331 _dprintf("%s: busy, not saving\n", __FUNCTION__); 332 } 333 else { 334 _dprintf("%s: cp %s %s\n", __FUNCTION__, hgz, tmp); 335 if (eval("cp", hgz, tmp) == 0) { 336 _dprintf("%s: copy ok\n", __FUNCTION__); 337 338 if (!nvram_match("rstats_bak", "0")) { 339 now = time(0); 340 tms = localtime(&now); 341 if (lastbak != tms->tm_yday) { 342 strcpy(bak, save_path); 343 n = strlen(bak); 344 if ((n > 3) && (strcmp(bak + (n - 3), ".gz") == 0)) n -= 3; 345 strcpy(bkp, bak); 346 for (b = HI_BACK-1; b > 0; --b) { 347 sprintf(bkp + n, "_%d.bak", b + 1); 348 sprintf(bak + n, "_%d.bak", b); 349 rename(bak, bkp); 350 } 351 if (eval("cp", "-p", save_path, bak) == 0) lastbak = tms->tm_yday; 352 } 353 } 354 355 _dprintf("%s: rename %s %s\n", __FUNCTION__, tmp, save_path); 356 if (rename(tmp, save_path) == 0) { 357 _dprintf("%s: rename ok\n", __FUNCTION__); 358 break; 359 } 360 } 361 } 362 363 // might not be ready 364 sleep(3); 365 if (gotterm) break; 366 } 367 } 368} 369 370static int decomp(const char *fname, void *buffer, int size, int max) 371{ 372 char s[256]; 373 int n; 374 FILE *fp; 375 long file_size = 0; 376 377 _dprintf("%s: fname=%s\n", __FUNCTION__, fname); 378 379 unlink(uncomp_fn); 380 381 n = 0; 382 sprintf(s, "gzip -dc %s > %s", fname, uncomp_fn); 383 if (system(s)) { 384 _dprintf("%s: %s != 0\n", __func__, s); 385 goto exit_decomp; 386 } 387 if (!(fp = fopen(uncomp_fn, "r"))) 388 goto exit_decomp; 389 390 fseek(fp, 0, SEEK_END); 391 file_size = ftell(fp); 392 fclose(fp); 393 if ((size * max) != file_size) { 394 _dprintf("%s: filesize mismatch! (%ld/%ld)\n", (size * max), file_size); 395 goto exit_decomp; 396 } 397 398 n = f_read(uncomp_fn, buffer, size * max); 399 _dprintf("%s: n=%d\n", __func__, n); 400 if (n <= 0) 401 n = 0; 402 else 403 n = n / size; 404 405exit_decomp: 406 unlink(uncomp_fn); 407 memset((char *)buffer + (size * n), 0, (max - n) * size); 408 409 return n; 410} 411 412static void clear_history(void) 413{ 414 memset(&history, 0, sizeof(history)); 415 history.id = CURRENT_ID; 416} 417 418static int load_history(const char *fname) 419{ 420 history_t hist; 421 422 _dprintf("%s: fname=%s\n", __FUNCTION__, fname); 423 424 if ((decomp(fname, &hist, sizeof(hist), 1) != 1) || (hist.id != CURRENT_ID)) { 425 history_v0_t v0; 426 427 if ((decomp(fname, &v0, sizeof(v0), 1) != 1) || (v0.id != ID_V0)) { 428 _dprintf("%s: load failed\n", __FUNCTION__); 429 return 0; 430 } 431 else { 432 // --- temp conversion --- 433 clear_history(); 434 435 // V0 -> V1 436 history.id = CURRENT_ID; 437 memcpy(history.daily, v0.daily, sizeof(history.daily)); 438 history.dailyp = v0.dailyp; 439 memcpy(history.monthly, v0.monthly, sizeof(v0.monthly)); // v0 is just shorter 440 history.monthlyp = v0.monthlyp; 441 } 442 } 443 else { 444 memcpy(&history, &hist, sizeof(history)); 445 } 446 447 _dprintf("%s: dailyp=%d monthlyp=%d\n", __FUNCTION__, history.dailyp, history.monthlyp); 448 return 1; 449} 450 451/* Try loading from the backup versions. 452 * We'll try from oldest to newest, then 453 * retry the requested one again last. In case the drive mounts while 454 * we are trying to find a good version. 455 */ 456static int try_hardway(const char *fname) 457{ 458 char fn[256]; 459 int n, b, found = 0; 460 461 strcpy(fn, fname); 462 n = strlen(fn); 463 if ((n > 3) && (strcmp(fn + (n - 3), ".gz") == 0)) 464 n -= 3; 465 for (b = HI_BACK; b > 0; --b) { 466 sprintf(fn + n, "_%d.bak", b); 467 found |= load_history(fn); 468 } 469 found |= load_history(fname); 470 471 return found; 472} 473 474static void load_new(void) 475{ 476 char hgz[256]; 477 478 sprintf(hgz, "%s.gz.new", history_fn); 479 if (load_history(hgz)) save(0); 480 unlink(hgz); 481} 482 483static void load(int new) 484{ 485 int i; 486 long t; 487 char *bi, *bo; 488 int n; 489 char hgz[256]; 490 char sp[sizeof(save_path)]; 491 unsigned char mac[6]; 492 493 current_uptime = uptime(); 494 495 strlcpy(save_path, nvram_safe_get("rstats_path"), sizeof(save_path) - 32); 496 if (((n = strlen(save_path)) > 0) && (save_path[n - 1] == '/')) { 497#ifdef RTCONFIG_RGMII_BRCM5301X 498 ether_atoe(nvram_safe_get("et1macaddr"), mac); 499#else 500 ether_atoe(nvram_safe_get("et0macaddr"), mac); 501#endif 502#ifdef RTCONFIG_GMAC3 503 if(nvram_match("gmac3_enable", "1")) 504 ether_atoe(nvram_safe_get("et2macaddr"), mac); 505#endif 506 sprintf(save_path + n, "tomato_rstats_%02x%02x%02x%02x%02x%02x.gz", 507 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 508 } 509 510 if (f_read("/var/lib/misc/rstats-stime", &save_utime, sizeof(save_utime)) != sizeof(save_utime)) { 511 save_utime = 0; 512 } 513 t = current_uptime + get_stime(); 514 if ((save_utime < current_uptime) || (save_utime > t)) save_utime = t; 515 //_dprintf("%s: uptime = %dm, save_utime = %dm\n", __FUNCTION__, current_uptime / 60, save_utime / 60); 516 517 // 518 519 sprintf(hgz, "%s.gz", speed_fn); 520 speed_count = decomp(hgz, speed, sizeof(speed[0]), MAX_SPEED_IF); 521 _dprintf("%s: speed_count = %d\n", __FUNCTION__, speed_count); 522 523 for (i = 0; i < speed_count; ++i) { 524 if (speed[i].utime > current_uptime) { 525 speed[i].utime = current_uptime; 526 speed[i].sync = 1; 527 } 528 } 529 530 // 531 532 sprintf(hgz, "%s.gz", history_fn); 533 534 if (new) { 535 unlink(hgz); 536 save_utime = 0; 537 return; 538 } 539 540 f_read_string(source_fn, sp, sizeof(sp)); // always terminated 541 _dprintf("%s: read source=%s save_path=%s\n", __FUNCTION__, sp, save_path); 542 if ((strcmp(sp, save_path) == 0) && (load_history(hgz))) { 543 _dprintf("%s: using local file\n", __FUNCTION__); 544 return; 545 } 546 547 if (save_path[0] != 0) { 548 if (strcmp(save_path, "*nvram") == 0) { 549 if (!wait_action_idle(60)) exit(0); 550 551 bi = nvram_safe_get("rstats_data"); 552 if ((n = strlen(bi)) > 0) { 553 if ((bo = malloc(base64_decoded_len(n))) != NULL) { 554 n = base64_decode(bi, bo, n); 555 _dprintf("%s: nvram n=%d\n", __FUNCTION__, n); 556 f_write(hgz, bo, n, 0, 0); 557 free(bo); 558 load_history(hgz); 559 } 560 } 561 } 562 else { 563 i = 1; 564 while (1) { 565 if (wait_action_idle(10)) { 566 567 // cifs quirk: try forcing refresh 568 eval("ls", save_path); 569 570 /* If we can't access the path, keep trying - maybe it isn't mounted yet. 571 * If we can, and we can sucessfully load it, oksy. 572 * If we can, and we cannot load it, then maybe it has been deleted, or 573 * maybe it's corrupted (like 0 bytes long). 574 * In these cases, try the backup files. 575 */ 576 if (load_history(save_path) || try_hardway(save_path)) { 577 f_write_string(source_fn, save_path, 0, 0); 578 break; 579 } 580 } 581 582 // not ready... 583 sleep(i); 584 if ((i *= 2) > 900) i = 900; // 15m 585 586 if (gotterm) { 587 save_path[0] = 0; 588 return; 589 } 590 591 if (i > (3 * 60)) { 592 syslog(LOG_WARNING, "Problem loading %s. Still trying...", save_path); 593 } 594 } 595 } 596 } 597} 598 599static void save_speedjs(long next) 600{ 601 int i, j, k; 602 speed_t *sp; 603 int p; 604 FILE *f; 605 uint64_t total; 606 uint64_t tmax; 607 unsigned long n; 608 char c; 609 610 if ((f = fopen("/var/tmp/rstats-speed.js", "w")) == NULL) return; 611 612 _dprintf("%s: speed_count = %d\n", __FUNCTION__, speed_count); 613 614 fprintf(f, "\nspeed_history = {\n"); 615 616 for (i = 0; i < speed_count; ++i) { 617 sp = &speed[i]; 618 fprintf(f, "%s'%s': {\n", i ? " },\n" : "", sp->ifname); 619 for (j = 0; j < MAX_COUNTER; ++j) { 620 total = tmax = 0; 621 fprintf(f, "%sx: [", j ? ",\n t" : " r"); 622 p = sp->tail; 623 for (k = 0; k < MAX_NSPEED; ++k) { 624 p = (p + 1) % MAX_NSPEED; 625 n = sp->speed[p][j]; 626 fprintf(f, "%s%lu", k ? "," : "", n); 627 total += n; 628 if (n > tmax) tmax = n; 629 } 630 fprintf(f, "],\n"); 631 632 c = j ? 't' : 'r'; 633 fprintf(f, " %cx_avg: %llu,\n %cx_max: %llu,\n %cx_total: %llu", 634 c, total / MAX_NSPEED, c, tmax, c, total); 635 } 636 } 637 fprintf(f, "%s_next: %ld};\n", speed_count ? "},\n" : "", ((next >= 1) ? next : 1)); 638 fclose(f); 639 640 rename("/var/tmp/rstats-speed.js", "/var/spool/rstats-speed.js"); 641} 642 643 644static void save_datajs(FILE *f, int mode) 645{ 646 data_t *data; 647 int p; 648 int max; 649 int k, kn; 650 651_dprintf("save_datajs:\n"); 652 fprintf(f, "\n%s_history = [\n", (mode == DAILY) ? "daily" : "monthly"); 653 654 if (mode == DAILY) { 655 data = history.daily; 656 p = history.dailyp; 657 max = MAX_NDAILY; 658_dprintf("DAILY: p= %d\n", p); 659 } 660 else { 661 data = history.monthly; 662 p = history.monthlyp; 663 max = MAX_NMONTHLY; 664_dprintf("MONTHLY: p= %d\n", p); 665 } 666 kn = 0; 667 for (k = max; k > 0; --k) { 668 p = (p + 1) % max; 669 if (data[p].xtime == 0) continue; 670 fprintf(f, "%s[0x%lx,0x%llx,0x%llx]", kn ? "," : "", 671 (unsigned long)data[p].xtime, data[p].counter[0] / K, data[p].counter[1] / K); 672 ++kn; 673_dprintf("%d:: [0x%lx,0x%llx,0x%llx]\n", p, 674 (unsigned long)data[p].xtime, data[p].counter[0] / K, data[p].counter[1] / K); 675 } 676 fprintf(f, "];\n"); 677} 678 679static void save_histjs(void) 680{ 681 FILE *f; 682 683 if ((f = fopen("/var/tmp/rstats-history.js", "w")) != NULL) { 684 save_datajs(f, DAILY); 685 save_datajs(f, MONTHLY); 686 fclose(f); 687 rename("/var/tmp/rstats-history.js", "/var/spool/rstats-history.js"); 688 } 689} 690 691 692static void bump(data_t *data, int *tail, int max, uint32_t xnow, unsigned long long *counter) 693{ 694 int t, i; 695 t = *tail; 696 if (data[t].xtime != xnow) { 697 for (i = max - 1; i >= 0; --i) { 698 if (data[i].xtime == xnow) { 699 t = i; 700 break; 701 } 702 } 703 if (i < 0) { 704 *tail = t = (t + 1) % max; 705 data[t].xtime = xnow; 706 memset(data[t].counter, 0, sizeof(data[0].counter)); 707 } 708 } 709 for (i = 0; i < MAX_COUNTER; ++i) { 710 data[t].counter[i] += counter[i]; 711 } 712} 713 714/** 715 * Convert ifname_desc returned by netdev_calc() to if_id enumeration. 716 * @desc: Pointer to "INTERNET", "WIRED", "BRIDGE", etc 717 * Ref to netdev_calc(). 718 * @return: 719 * -1: invalid parameter 720 * if_id enumeration 721 */ 722static enum if_id desc_to_id(char *desc) 723{ 724 enum if_id id = IFID_MAX; 725 char *d = desc + 9, *s = desc + 10; 726 727 if (!desc) 728 return -1; 729 730 if (!strcmp(desc, "INTERNET")) 731 id = IFID_INTERNET; 732 else if (!strcmp(desc, "INTERNET1")) 733 id = IFID_INTERNET1; 734 else if (!strcmp(desc, "WIRED")) 735 id = IFID_WIRED; 736 else if (!strcmp(desc, "BRIDGE")) 737 id = IFID_BRIDGE; 738 else if (!strncmp(desc, "WIRELESS0", 9)) { 739 if (*d == '\0') 740 id = IFID_WIRELESS0; 741 else if (*d == '.' && *s >= '0' && *s <= '2' && *(s + 1) == '\0') 742 id = IFID_WIRELESS0 + *s - '0' + 1; 743 } else if (!strncmp(desc, "WIRELESS1", 9)) { 744 if (*d == '\0') 745 id = IFID_WIRELESS1; 746 else if (*d == '.' && *s >= '0' && *s <= '2' && *(s + 1) == '\0') 747 id = IFID_WIRELESS1 + *s - '0' + 1; 748 } else if (!strncmp(desc, "WIRELESS2", 9)) { 749 if (*d == '\0') 750 id = IFID_WIRELESS2; 751 else if (*d == '.' && *s >= '0' && *s <= '2' && *(s + 1) == '\0') 752 id = IFID_WIRELESS2 + *s - '0' + 1; 753 } 754 755 if (id < 0 || id == IFID_MAX) 756 _dprintf("%s: Unknown desc [%s]\n", __func__, desc); 757 758 return id; 759 760} 761 762static void calc(void) 763{ 764 FILE *f; 765 char buf[256]; 766 char *ifname; 767 char ifname_desc[12], ifname_desc2[12]; 768 char *p; 769 unsigned long long counter[MAX_COUNTER]; 770 unsigned long long rx2, tx2; 771 speed_t *sp; 772 int i, j, t; 773 time_t now; 774 time_t mon; 775 struct tm *tms; 776 uint32_t c; 777 uint32_t sc; 778 unsigned long long diff; 779 long tick; 780 int n; 781 char *exclude; 782 enum if_id id; 783 struct tmp_speed_s { 784 char desc[20]; 785 unsigned long long counter[MAX_COUNTER]; 786 } tmp_speed[IFID_MAX], *tmp; 787#ifdef RTCONFIG_ISP_METER 788 char traffic[64]; 789#endif 790 791#ifdef RTCONFIG_QTN 792 qcsapi_unsigned_int l_counter_value; 793#endif 794 795 rx2 = 0; 796 tx2 = 0; 797 now = time(0); 798 exclude = nvram_safe_get("rstats_exclude"); 799 800 if ((f = fopen("/proc/net/dev", "r")) == NULL) return; 801 fgets(buf, sizeof(buf), f); // header 802 fgets(buf, sizeof(buf), f); // " 803 memset(tmp_speed, 0, sizeof(tmp_speed)); 804 while (fgets(buf, sizeof(buf), f)) { 805 if ((p = strchr(buf, ':')) == NULL) continue; 806 //_dprintf("\n=== %s\n", buf); 807 *p = 0; 808 if ((ifname = strrchr(buf, ' ')) == NULL) ifname = buf; 809 else ++ifname; 810 if ((strcmp(ifname, "lo") == 0) || (find_word(exclude, ifname))) continue; 811 812 // <rx bytes, packets, errors, dropped, fifo errors, frame errors, compressed, multicast><tx ...> 813 if (sscanf(p + 1, "%llu%*u%*u%*u%*u%*u%*u%*u%llu", &counter[0], &counter[1]) != 2) continue; 814 815//TODO: like httpd/web.c ej_netdev() 816#ifdef RTCONFIG_BCM5301X_TRAFFIC_MONITOR 817 if(strncmp(ifname, "vlan", 4)==0){ 818 traffic_wanlan(ifname, &counter[0], &counter[1]); 819 } 820#endif 821 822 if (!netdev_calc(ifname, ifname_desc, (unsigned long*) &counter[0], (unsigned long*) &counter[1], ifname_desc2, (unsigned long*) &rx2, (unsigned long*) &tx2)) 823 continue; 824 //_dprintf(">>> %s, %s, %llu, %llu, %s, %llu, %llu <<<\n",ifname, ifname_desc, counter[0], counter[1], ifname_desc2, rx2, tx2); 825#ifdef RTCONFIG_QTN 826 if (!strcmp(ifname, nvram_safe_get("wl_ifname"))) 827 strcpy(ifname_desc2, "WIRELESS1"); 828#endif 829loopagain: 830 831 id = desc_to_id(ifname_desc); 832 if (id < 0 || id >= IFID_MAX) 833 continue; 834 tmp = &tmp_speed[id]; 835 strcpy(tmp->desc, ifname_desc); 836 for (i = 0; i < ARRAY_SIZE(tmp->counter); ++i) 837 tmp->counter[i] += counter[i]; 838 839#ifdef RTCONFIG_QTN //RT-AC87 840 if(!rpc_qtn_ready()) continue; 841 if (strlen(ifname_desc2)) 842 { 843 strcpy(ifname_desc, ifname_desc2); 844 qcsapi_interface_get_counter(WIFINAME, qcsapi_total_bytes_received, &l_counter_value); 845 counter[0] = l_counter_value; 846 qcsapi_interface_get_counter(WIFINAME, qcsapi_total_bytes_sent, &l_counter_value); 847 counter[1] = l_counter_value; 848 strcpy(ifname_desc2, ""); 849 goto loopagain; 850 } 851#else 852 if (strlen(ifname_desc2)) 853 { 854 strcpy(ifname_desc, ifname_desc2); 855 counter[0] = rx2; 856 counter[1] = tx2; 857 strcpy(ifname_desc2, ""); 858 goto loopagain; 859 } 860 861#endif 862 } 863 fclose(f); 864 865 for (t = 0, tmp = tmp_speed; t < ARRAY_SIZE(tmp_speed); ++t, ++tmp) { 866 /* skip unused item. */ 867 if (tmp->desc[0] == '\0') 868 continue; 869 870 sp = speed; 871 for (i = speed_count; i > 0; --i) { 872 if (strcmp(sp->ifname, tmp->desc) == 0) break; 873 ++sp; 874 } 875 876 if (i == 0) { 877 if (speed_count >= MAX_SPEED_IF) continue; 878 879 //_dprintf("%s: add %s as #%d\n", __FUNCTION__, ifname_desc, speed_count); 880 881 i = speed_count++; 882 sp = &speed[i]; 883 memset(sp, 0, sizeof(*sp)); 884 strcpy(sp->ifname, tmp->desc); 885 sp->sync = 1; 886 sp->utime = current_uptime; 887 } 888 if (sp->sync) { 889 //_dprintf("%s: sync %s\n", __FUNCTION__, ifname_desc); 890 sp->sync = -1; 891 892 memcpy(sp->last, tmp->counter, sizeof(sp->last)); 893 memset(tmp->counter, 0, sizeof(tmp->counter)); 894 } 895 else { 896 897 sp->sync = -1; 898 899 tick = current_uptime - sp->utime; 900 n = tick / INTERVAL; 901 902 sp->utime += (n * INTERVAL); 903 //_dprintf("%s: %s n=%d tick=%d\n", __FUNCTION__, ifname, n, tick); 904 905 for (i = 0; i < MAX_COUNTER; ++i) { 906 c = tmp->counter[i]; 907 sc = sp->last[i]; 908 if (c < sc) { 909 diff = (0xFFFFFFFF - sc + 1) + c; 910 if (diff > MAX_ROLLOVER) diff = 0; 911 } 912 else { 913 diff = c - sc; 914 } 915 sp->last[i] = c; 916 tmp->counter[i] = diff; 917 } 918 919 for (j = 0; j < n; ++j) { 920 sp->tail = (sp->tail + 1) % MAX_NSPEED; 921 for (i = 0; i < MAX_COUNTER; ++i) { 922 sp->speed[sp->tail][i] = tmp->counter[i] / n; 923 } 924 } 925 } 926 927 // todo: split, delay 928 929 if (now > Y2K && strcmp(tmp->desc, "INTERNET")==0) { 930 /* Skip this if the time&date is not set yet */ 931 /* Skip non-INTERNET interface only */ 932 tms = localtime(&now); 933 bump(history.daily, &history.dailyp, MAX_NDAILY, 934 (tms->tm_year << 16) | ((uint32_t)tms->tm_mon << 8) | tms->tm_mday, tmp->counter); 935 n = nvram_get_int("rstats_offset"); 936 if ((n < 1) || (n > 31)) n = 1; 937 mon = now + ((1 - n) * (60 * 60 * 24)); 938 tms = localtime(&mon); 939 bump(history.monthly, &history.monthlyp, MAX_NMONTHLY, 940 (tms->tm_year << 16) | ((uint32_t)tms->tm_mon << 8), tmp->counter); 941#ifdef RTCONFIG_ISP_METER 942 today_rx = last_day_rx + (history.daily[history.dailyp].counter[0]/K); 943 today_tx = last_day_tx + (history.daily[history.dailyp].counter[1]/K); 944 memset(traffic, 0, 64); 945 sprintf(traffic, "%lu", today_rx); 946 nvram_set("isp_day_rx", traffic); 947 memset(traffic, 0, 64); 948 sprintf(traffic, "%lu", today_tx); 949 nvram_set("isp_day_tx", traffic); 950 month_rx = last_month_rx + (history.monthly[history.monthlyp].counter[0]/K) - reset_base_month_rx; 951 month_tx = last_month_tx + (history.monthly[history.monthlyp].counter[1]/K) - reset_base_month_tx; 952 memset(traffic, 0, 64); 953 sprintf(traffic, "%lu", month_rx); 954 nvram_set("isp_month_rx", traffic); 955 memset(traffic, 0, 64); 956 sprintf(traffic, "%lu", month_tx); 957 nvram_set("isp_month_tx", traffic); 958#ifdef DEBUG 959_dprintf("CUR MONTH Rx= %lu = %lu + %llu - %lu\n",month_rx,last_month_rx,(history.monthly[history.monthlyp].counter[0]/K), reset_base_month_rx); 960_dprintf("CUR MONTH Tx= %lu = %lu + %llu - %lu\n",month_tx,last_month_tx,(history.monthly[history.monthlyp].counter[0]/K), reset_base_month_tx); 961#endif 962#endif 963 } 964 } 965 966 // cleanup stale entries 967 for (i = 0; i < speed_count; ++i) { 968 sp = &speed[i]; 969 if (sp->sync == -1) { 970 sp->sync = 0; 971 continue; 972 } 973 if (((current_uptime - sp->utime) > (10 * SMIN)) || (find_word(exclude, sp->ifname))) { 974 _dprintf("%s: #%d removing. > time limit or excluded\n", __FUNCTION__, i); 975 --speed_count; 976 memcpy(sp, sp + 1, (speed_count - i) * sizeof(speed[0])); 977 } 978 else { 979 _dprintf("%s: %s not found setting sync=1\n", __FUNCTION__, sp->ifname, i); 980 sp->sync = 1; 981 } 982 } 983 984 // todo: total > user 985 if (current_uptime >= save_utime) { 986 save(0); 987 save_utime = current_uptime + get_stime(); 988 _dprintf("%s: uptime = %dm, save_utime = %dm\n", __FUNCTION__, current_uptime / 60, save_utime / 60); 989 } 990} 991 992static void sig_handler(int sig) 993{ 994 switch (sig) { 995 case SIGTERM: 996 case SIGINT: 997 gotterm = 1; 998 break; 999 case SIGHUP: 1000 gothup = 1; 1001 break; 1002 case SIGUSR1: 1003 gotuser = 1; 1004 break; 1005 case SIGUSR2: 1006 gotuser = 2; 1007 break; 1008 } 1009} 1010 1011int main(int argc, char *argv[]) 1012{ 1013 struct sigaction sa; 1014 long z; 1015 int new; 1016#ifdef RTCONFIG_ISP_METER 1017 long zzz, pppd_uptime, pppd_conntime, isp_connect_time; 1018 FILE *fp; 1019 char isp_meter_buf[64]; 1020 unsigned long isp_rx, isp_tx; 1021 int get_connect_time; 1022 struct timeval timenow; 1023#endif 1024 1025 printf("rstats\nCopyright (C) 2006-2009 Jonathan Zarate\n\n"); 1026 1027 if (fork() != 0) return 0; 1028 1029 openlog("rstats", LOG_PID, LOG_USER); 1030 1031 new = 0; 1032 if (argc > 1) { 1033 if (strcmp(argv[1], "--new") == 0) { 1034 new = 1; 1035 _dprintf("new=1\n"); 1036 } 1037 } 1038 1039 clear_history(); 1040 unlink("/var/tmp/rstats-load"); 1041 1042 sa.sa_handler = sig_handler; 1043 sa.sa_flags = 0; 1044 sigemptyset(&sa.sa_mask); 1045 sigaction(SIGUSR1, &sa, NULL); 1046 sigaction(SIGUSR2, &sa, NULL); 1047 sigaction(SIGHUP, &sa, NULL); 1048 sigaction(SIGTERM, &sa, NULL); 1049 sigaction(SIGINT, &sa, NULL); 1050#ifdef RTCONFIG_ISP_METER 1051 signal(SIGTSTP, reset_traffic_meter_counter); 1052 1053 get_connect_time = 0; 1054 reset_base_day_rx = 0; 1055 reset_base_day_tx = 0; 1056 reset_base_month_rx = 0; 1057 reset_base_month_tx = 0; 1058 isp_limit = nvram_get_int("isp_limit"); 1059 last_day_rx = nvram_get_int("isp_day_rx"); 1060 last_day_tx = nvram_get_int("isp_day_tx"); 1061 last_month_rx = nvram_get_int("isp_month_rx"); 1062 last_month_tx = nvram_get_int("isp_month_tx"); 1063 isp_limit_time = nvram_get_int("isp_limit_time"); 1064 last_connect_time = nvram_get_int("isp_connect_time"); 1065#ifdef DEBUG 1066_dprintf("rstats get last data from nvram:\n"); 1067_dprintf("day rx= %lu\n", last_day_rx); 1068_dprintf("day tx= %lu\n", last_day_tx); 1069_dprintf("mon rx= %lu\n", last_month_rx); 1070_dprintf("mon tx= %lu\n", last_month_tx); 1071_dprintf("limit = %d\n", isp_limit); 1072_dprintf("L_time= %ld\n",isp_limit_time); 1073#endif 1074 memset(isp_meter_buf, 0, sizeof(isp_meter_buf)); 1075 get_meter_file(isp_meter_buf); 1076 if(isp_meter_buf!=NULL) { 1077 if (sscanf(isp_meter_buf, "isp_meter:%lu,%lu,%ld,end", &isp_rx, &isp_tx, &isp_connect_time) == 3) { 1078 _dprintf("isp_rx= %lu, isp_tx= %lu, isp_connent_time= %ld\n", 1079 isp_rx, isp_tx, isp_connect_time); 1080 if((isp_rx>last_month_rx)&&(isp_tx>last_month_tx)){ 1081 last_month_rx = isp_rx; 1082 last_month_tx = isp_tx; 1083 } 1084 if(isp_connect_time > last_connect_time) 1085 last_connect_time = isp_connect_time; 1086 } 1087 } 1088 else { 1089 isp_rx = 0; 1090 isp_tx = 0; 1091 last_connect_time = 0; 1092 } 1093#ifdef DEBUG 1094_dprintf("Update last data from mtd:\n"); 1095_dprintf("mon rx= %lu\n", last_month_rx); 1096_dprintf("mon tx= %lu\n", last_month_tx); 1097_dprintf("last_t= %ld\n", last_connect_time); 1098#endif 1099 month_rx = last_month_rx; 1100 month_tx = last_month_tx; 1101 1102 zzz = current_uptime = uptime(); 1103#endif 1104 load(new); 1105 1106 z = current_uptime = uptime(); 1107 1108 while (1) { 1109 while (current_uptime < z) { 1110 sleep(z - current_uptime); 1111 if (gothup) { 1112 if (unlink("/var/tmp/rstats-load") == 0) load_new(); 1113 else save(0); 1114 gothup = 0; 1115 } 1116 if (gotterm) { 1117 save(!nvram_match("rstats_sshut", "1")); 1118 exit(0); 1119 } 1120 if (gotuser == 1) { 1121 save_speedjs(z - uptime()); 1122 gotuser = 0; 1123 } 1124 else if (gotuser == 2) { 1125 save_histjs(); 1126 gotuser = 0; 1127 } 1128 current_uptime = uptime(); 1129 } 1130 calc(); 1131 z += INTERVAL; 1132 1133#ifdef RTCONFIG_ISP_METER 1134 gettimeofday(&timenow, NULL); 1135#ifdef DEBUG 1136 _dprintf("********************************\n"); 1137 _dprintf(" now time = %ld\n", timenow.tv_sec); 1138#endif 1139 if((fp=fopen("/var/pppd_time", "r"))!=NULL) { 1140 fgets(isp_meter_buf, sizeof(isp_meter_buf), fp); 1141 fclose(fp); 1142 if( sscanf(isp_meter_buf, "uptime:%ld", &pppd_uptime) == 1 ) { 1143 cur_conn_time = timenow.tv_sec - pppd_uptime; 1144#ifdef DEBUG 1145 _dprintf(" up time = %ld\n", pppd_uptime); 1146 _dprintf(" cur_conn time = %ld\n", cur_conn_time); 1147#endif 1148 total_connect_time = last_connect_time + cur_conn_time - reset_base_time; 1149 get_connect_time = 0; 1150 } 1151 else if( (sscanf(isp_meter_buf, "conntime:%ld", &pppd_conntime)==1) && get_connect_time==0 ) { 1152#ifdef DEBUG 1153 _dprintf(" last connect time = %ld\n", pppd_conntime); 1154#endif 1155 last_connect_time += pppd_conntime - reset_base_time; 1156 total_connect_time = last_connect_time; 1157 reset_base_time = 0; 1158 get_connect_time = 1; 1159 } 1160 memset(isp_meter_buf, 0, sizeof(isp_meter_buf)); 1161 } 1162#ifdef DEBUG 1163 _dprintf(" reset_base_time = %ld\n", reset_base_time); 1164 _dprintf(" total_connect_time= %ld\n", total_connect_time); 1165 _dprintf("******************************** %ld\n", z); 1166#endif 1167//_dprintf("isp_meter= %s\n", nvram_get("isp_meter")); 1168 if(!nvram_match("isp_meter", "disable")) { 1169 isp_limit = nvram_get_int("isp_limit"); 1170#ifdef DEBUG 1171_dprintf("* Month: tx= %lu, rx= %lu \n", month_tx, month_rx); 1172_dprintf("* isplimit = %d\n", isp_limit); 1173_dprintf("* wan_state= %s\n", nvram_get("wan0_state_t")); 1174#endif 1175 if(nvram_match("wan0_state_t", "2")) { //Connected 1176 if(nvram_match("isp_meter", "download")) { 1177 if(month_rx > (isp_limit*1000)) 1178 notify_rc_and_wait("isp_meter down"); 1179 } 1180 else if(nvram_match("isp_meter", "both")) { 1181 if((month_tx)+(month_rx) > (isp_limit*1000)) 1182 notify_rc_and_wait("isp_meter down"); 1183 } 1184 else if(nvram_match("isp_meter", "time")) { 1185 if(total_connect_time > (isp_limit_time*60)) { 1186 notify_rc_and_wait("isp_meter down"); 1187 cur_conn_time = 0; 1188 } 1189 } 1190 } 1191 1192 //Write to Flash 1193 if(current_uptime - zzz >= MTD_WRITE_INTERVEL) { 1194 nvram_commit(); 1195 sprintf(isp_meter_buf,"isp_meter:%lu,%lu,%ld,end", month_rx, month_tx, total_connect_time); 1196#ifdef DEBUG 1197_dprintf("*WRITE: %s\n", isp_meter_buf); 1198#endif 1199 set_meter_file(isp_meter_buf); 1200 zzz = current_uptime; 1201 } 1202 } 1203#endif //RTCONFIG_ISP_METER 1204 } 1205 1206 return 0; 1207} 1208