Шейпер трафика на cpp под FreeBSD

Вот нашел в своих старых файлах.  Пытался когда-то переписать шейпер с PHP на cpp, думал что выигрыш в скорости работы получу. Не получил ничего кроме усложнения 😉 Потому осталось в «столе» и в продакшен не пошло. Узкоспециализированная разработка, использовать которую вот так просто не получится. Выложил для «истории», чтоб не потерялась если что..

/* 
 * File:   main.cpp
 * Author: Грибов Павел
 * http://грибовы.рф
 *
 * Created on 16 ноября 2015 г., 15:07
 */

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <unistd.h>
#include <cstring>
#include <fstream>
#include <sstream>
#include <math.h>
#include <my_global.h>
#include <mysql.h>


using namespace std;
char ver[]="1.0.1";  // версия программы
int debug;           // 1 -  если отладка
int noc=0;            // 1 -  автономно от НОС
int simula=0;        // "симуляция" запуска. 
int curtfaff=0;      // текущий трафик на интрефейсе
int current_time=0;  // текущая метка времени UNIX
int old_curtfaff=0;      // трафик с предыдущего запуска на интрефейсе
int old_current_time=0;  // время предыдущего запуска
float current_percent=1;           // текущий % скорости от номинала
int sec=0;               // время прошедшее с предыдущего запуска
int delta=0;         // трафик за секунду
int delta_old=0;     // перыдущее значение трафика за секунду
int delta_a=0;       // ускорение
float lg=0;            //логарифм
float kofdec=0;        //коэффициент увеличения скорости
float kofinc=0;        //коэффициент уменьшения скорости                                                                                                                                                                                                                       
float kofmin=30;       //минамальный процент скорости абонента от базовой                                                                                                                                                                                                      
char hostname[1024]; // имя машины где запустили шейпер                                                                                                                                                                                                                        
char hostbase[1024]; // IP где расположена база НОС                                                                                                                                                                                                                            
char userbase[1024]; // имя пользователя где расположена база НОС                                                                                                                                                                                                              
char passbase[1024]; // пароль пользователя где расположена база НОС                                                                                                                                                                                                           
char namebase[1024]; // имя базы НОС                                                                                                                                                                                                                                           
char tokd[1024];    // сдвиг токена                                                                                                                                                                                                                                            
int token;  //сдвиг токена                                                                                                                                                                                                                                                     
string sql;          // переменная для хранения запросов                                                                                                                                                                                                                       
struct tars{                                                                                                                                                                                                                                                                   
 int tar_id;                                                                                                                                                                                                                                                                   
 string tar_name;                                                                                                                                                                                                                                                              
 int fixshape;                                                                                                                                                                                                                                                                 
 int used;                                                                                                                                                                                                                                                                     
 int maxspeed;                                                                                                                                                                                                                                                                 
 int onlytar;                                                                                                                                                                                                                                                                  
 };                                                                                                                                                                                                                                                                            
 tars *gtars;                                                                                                                                                                                                                                                                  
 struct users{                                                                                                                                                                                                                                                                 
  string ip; //ip абонента                                                                                                                                                                                                                                                     
  int b_shape; //скорость по биллингу                                                                                                                                                                                                                                          
  int tar_id;   //тариф                                                                                                                                                                                                                                                        
  string login; //логин
  int vg_id;    //учетка
  int fixshape; // 1 фиксированная скорость вверх?
  int onlytar;  // 1 фиксировання скорость вниз?
  int real_speed_in; //текущая реальная скорость
  int real_speed_out; //текущая реальная скорость
  int pipe_in;  // труба входящая скорость
  int pipe_out; // труба исходящая скорость
 };
users *gusers; 
int counttar=0;     //количество тарифов
int countusers=0;
class sconf{
 public:
  int blibaseid; //идентификатор биллинга
  int wcanal;    //ширина канала
  int maxw;      //максимальная планка
  int minw;      //минимальная планка
  string ferma;  //какие подразделения обслуживает. Например 1,2
  string segments; //какие сегменты обслуживае
  string ent;       //интерфейс на котором меряем трафик
  string bhost;     //хост биллинга
  string failbhost; //резервный хост биллинга
  string bname;     //имя базы биллинга
  string buser;     //имя пользователя биллинга
  string bpass;     //пароль пользователя биллинга
  int maxperc;   //коэффициент умножения скорости
  int logkof;    //основание логарифма
  string agents;    //список обслуживаемых агентов 
  string external_traff_url;    //ссылка на внешний трафик    
};
sconf cfg;
MYSQL *connectionNOC;
MYSQL *connectionBilling;
MYSQL_RES *result;
MYSQL_ROW row;
int query_state;

string from_int(int number){
    stringstream ss;
    ss << number;
    return ss.str();
}
string from_float(float number){
    stringstream ss;
    ss << number;
    return ss.str();
}
string trim(string ss){
 int i=0;
 string st=""; 
 while(i!=ss.length()-1){
   if(ss[i]!=' '){st+=ss[i];};
   i++;
 };    
 return st;
};
int PutLog(string ss){    
 if (debug==1){printf("%s \n",ss.c_str());};   
};
int PutCurrentCfg(){
 if (debug==1){
    printf("----Агенты: %s \n",std::string(cfg.agents).c_str());
    printf("----Хост биллинга: %s \n",std::string(cfg.bhost).c_str());
    printf("----Какой биллинг: %i \n",cfg.blibaseid);
    printf("----Имя базы: %s \n",std::string(cfg.bname).c_str());
    printf("----Пароль базы: %s \n",std::string(cfg.bpass).c_str());
    printf("----Пользователь базы: %s \n",std::string(cfg.buser).c_str());
    printf("----Интерфейс сьема трафика: %s \n",std::string(cfg.ent).c_str());
    printf("----Внешняя ссылка забора трафика: %s \n",std::string(cfg.external_traff_url).c_str());
    printf("----Резервный IP биллинга: %s \n",std::string(cfg.failbhost).c_str());
    printf("----Обслуживаемые подразделения: %s \n",std::string(cfg.ferma).c_str());
    printf("----Основание логарифма: %i \n",cfg.logkof);
    printf("----Процент подьема скорости: %i \n",cfg.maxperc);
    printf("----Максимальная планка: %i \n",cfg.maxw);
    printf("----Минимальная планка: %i \n",cfg.minw);
    printf("----Обслуживаемые сегменты: %s \n",std::string(cfg.segments).c_str());
    printf("----Ширина канала: %i \n",cfg.wcanal);    
 };    
};
int help(){
          PutLog(ver);
          PutLog("Параметры запуска:");
          PutLog("-debug  : отображение подробной информации о работе программы");
          PutLog("-h [ip] : ip базы данных NOC");
          PutLog("-u [name] : имя пользователя базы данных NOC");
          PutLog("-p [name] : пароль базы данных NOC");
          PutLog("-b [name] : имя базы данных NOC");
          PutLog("-t [число] : сдвиг вычисления токена в случае конфликта");
          PutLog("-s включается режим симуляции. НЕ использовать!. Внутрення отладка!");
          PutLog("-help : помощь по ключам");
          PutLog("Пример запуска: ./shaper -h 11.11.11.11 -u user -p pass -b noc -debug");
          PutLog("(c) 2015-2016 Грибов Павел http://грибовы.рф");    
};
int GetCommandLine(int argc, char** argv){        
  int cnt;
  cnt=0;  
  strcat(passbase,"\0");
  strcat(userbase,"\0");
  strcat(hostbase,"\0");
  strcat(namebase,"\0");
  token=0;
  for (int i = 0; i < argc; i++) {
      if (std::string(argv[i])== "-debug"){
          PutLog(ver);
          printf("-run at debug mode\n");
          PutLog(ver);
          debug=1;
      };        
      if ((std::string(argv[i])== "-help") or (std::string(argv[i])== "/?") or (std::string(argv[i])== "--help") or (std::string(argv[i])== "/h")){          
          debug=1;
          help();
          exit(0);          
      };
      if (std::string(argv[i])== "-s"){          
          simula=1;
          PutLog("--режим симуляции работы (ubuntu)");          
      };              
      if (std::string(argv[i])== "-h"){          
          strcat(hostbase,argv[i+1]);
          PutLog("MySql host:");
          PutLog(hostbase);
      };        
      if (std::string(argv[i])== "-u"){          
          strcat(userbase,argv[i+1]);
          PutLog("MySql user:");
          PutLog(userbase);
      };        
      if (std::string(argv[i])== "-p"){          
          strcat(passbase,argv[i+1]);
          PutLog("MySql user pass:");
          PutLog(passbase);
      };        
      if (std::string(argv[i])== "-d"){          
          strcat(namebase,argv[i+1]);
          PutLog("MySql base name:");
          PutLog(namebase);
      };        
      if (std::string(argv[i])== "-t"){          
          strcat(tokd,argv[i+1]);
          token=atoi(tokd);
          PutLog("Сдвиг токена:");
          PutLog(tokd);
      };        
      
      cnt++;
    }      
  if (cnt==1){
          debug=1;
          PutLog(ver);
          PutLog("-help : помощь по ключам");
          exit(0);                
  };
};
int GetCommonConfig(){    
  PutLog("--узнаем где мы, и заполняем основные параметры.");    
  hostname[1023] = '\0';
  gethostname(hostname, 1023);  
  PutLog("--узнаем имя машины:");    
  PutLog(hostname);
  PutLog("--пробуем соедениться с базой НОС");    
  connectionNOC = mysql_init(NULL); 
  if(connectionNOC == NULL) {
    // Если дескриптор не получен - выводим сообщение об ошибке
    fprintf(stderr, "Error: не могу получить дискриптор соединения с MySQL\n");    
    exit(1);
  };   
  if (!mysql_real_connect(connectionNOC,hostbase,userbase,passbase,namebase,3306,0,0)){
    fprintf(stderr, "Error: не могу соедениться с НОС. Пробую работать автономно! %s\n",mysql_error(connectionNOC));        
    noc=1;      
  };  
  if (noc==0) {
    sql ="use noc";PutLog(sql);  
    if (mysql_query(connectionNOC, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query %s\n",mysql_error(connectionNOC));exit(1);};      
    PutLog("---успешно!");  
    result=mysql_store_result(connectionNOC);    
      
    sql ="SET NAMES utf8";PutLog(sql);  
    if (mysql_query(connectionNOC, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query %s\n",mysql_error(connectionNOC));exit(1);};      
    PutLog("---успешно!");  
    result=mysql_store_result(connectionNOC);    
    
    PutLog("--читаем настройки шейпера из НОС");  
    sql="SELECT lanbshconfig.* FROM lanbshaperservers inner join lanbshconfig on lanbshconfig.idsh=lanbshaperservers.id WHERE lanbshaperservers.sname='servername'";
    //sql.replace(sql.find("servername"),std::string (hostname).size(),hostname);
    sql.replace(sql.find("servername"),std::string ("servername").size(),hostname);
    if (simula==1){sql="SELECT lanbshconfig.* FROM lanbshaperservers inner join lanbshconfig on lanbshconfig.idsh=lanbshaperservers.id WHERE lanbshaperservers.sname='eos'";};
    PutLog(sql);     
    if (mysql_query(connectionNOC, sql.c_str()) != 0){
        fprintf(stderr,"Error: can't execute SQL-query %s\n",mysql_error(connectionNOC));
        exit(1);
    };
    result=mysql_store_result(connectionNOC);
    if(result == NULL) {
        fprintf(stderr,"Error: can't get the result description \n");
        exit(1);
    };
    int flag=0;
    while ((row = mysql_fetch_row(result)) != NULL){
      cfg.blibaseid=atoi(row[1]);
      cfg.agents=row[24];
      cfg.bhost=row[12];
      cfg.bname=row[13];
      cfg.buser=row[14];
      cfg.bpass=row[15];
      cfg.ent=row[11];
      cfg.external_traff_url=row[23];
      cfg.failbhost=row[17];
      cfg.ferma=row[8];
      cfg.logkof=atoi(row[21]);
      cfg.maxperc=atoi(row[16]);
      cfg.maxw=atoi(row[6]);
      cfg.minw=atoi(row[7]);
      cfg.segments=row[9];
      cfg.wcanal=atoi(row[5]);            
      flag=1;
      PutCurrentCfg();
    };
    if (flag==0){
        fprintf(stderr,"--- не удалось найти настройки для этого сервера в НОС.\n");
        exit(1);
    };
  } else {
     //ну а тут пробуем прочитать настройки из файла    
      PutLog("-- читаем файл /etc/shapercpp.cfg");
      ifstream F("/etc/shapercpp.cfg"); // открыли файл для чтения
      char buff[50];
      F.getline(buff,50);cfg.agents=std::string(buff);
      F.getline(buff,50);cfg.bhost=std::string(buff);
      F.getline(buff,50);cfg.blibaseid=atoi(buff);      
      F.getline(buff,50);cfg.bname=std::string(buff);
      F.getline(buff,50);cfg.bpass=std::string(buff);
      F.getline(buff,50);cfg.buser=std::string(buff);
      F.getline(buff,50);cfg.ent=std::string(buff);
      F.getline(buff,50);cfg.external_traff_url=std::string(buff);
      F.getline(buff,50);cfg.failbhost=std::string(buff);
      F.getline(buff,50);cfg.ferma=std::string(buff);
      F.getline(buff,50);cfg.logkof=atoi(std::string(buff).c_str());
      F.getline(buff,50);cfg.maxperc=atoi(std::string(buff).c_str());
      F.getline(buff,50);cfg.maxw=atoi(std::string(buff).c_str());
      F.getline(buff,50);cfg.minw=atoi(std::string(buff).c_str());
      F.getline(buff,50);cfg.segments=std::string(buff);
      F.getline(buff,50);cfg.wcanal=atoi(std::string(buff).c_str());
      PutLog("-- прочитали!");
      PutCurrentCfg();
      F.close();
  };
  if (noc!=1){
    //записываем настройки в файл
    PutLog("-- запись настроек в файл /etc/shapercpp.cfg");
    ofstream F;
    F.open("/etc/shapercpp.cfg");
    F<< cfg.agents;F<< "\n";
    F<< cfg.bhost;F<< "\n";
    F<< cfg.blibaseid;F<< "\n";
    F<< cfg.bname;F<< "\n";
    F<< cfg.bpass;F<< "\n";
    F<< cfg.buser;F<< "\n";
    F<< cfg.ent;F<< "\n";
    F<< cfg.external_traff_url;F<< "\n";
    F<< cfg.failbhost;F<< "\n";
    F<< cfg.ferma;F<< "\n";
    F<< cfg.logkof;F<< "\n";
    F<< cfg.maxperc;F<< "\n";
    F<< cfg.maxw;F<< "\n";
    F<< cfg.minw;F<< "\n";
    F<< cfg.segments;F<< "\n";
    F<< cfg.wcanal;F<< "\n";  
    F.close();
  };
  PutLog("--пробуем соедениться с биллингом по основному адресу");  
  connectionBilling = mysql_init(NULL); 
  if(connectionBilling == NULL) {
    // Если дескриптор не получен - выводим сообщение об ошибке
    fprintf(stderr, "Error: не могу получить дискриптор соединения с MySQL\n");    
    exit(1);
  };   
  if (!mysql_real_connect(connectionBilling,cfg.bhost.c_str(),cfg.buser.c_str(),cfg.bpass.c_str(),cfg.bname.c_str(),3306,0,0)){
    fprintf(stderr, "Error: не могу соедениться с биллингом.  %s\n",mysql_error(connectionNOC));        
    PutLog("--- пробую подключится к биллингу по резервному IP сервера");  
     if (!mysql_real_connect(connectionBilling,cfg.failbhost.c_str(),cfg.buser.c_str(),cfg.bpass.c_str(),cfg.bname.c_str(),3306,0,0)){
       fprintf(stderr, "Error: не могу соедениться с резервным биллингом.  %s\n",mysql_error(connectionNOC));        
       exit(1);
     }; 
  };  
  PutLog("--- ОК");  
};
int GetCurrentSpeed(){
  PutLog("--снимаю с интерфейса текущую скорость");
  char buf[10000]; 
  std::string s;
  sql="/usr/bin/netstat -nbI enterface | grep 'Link' | awk '{print $8}'|tr -d '\n'";
  //sql.replace(sql.find("enterface"),std::string (cfg.ent).size(),cfg.ent);   
  sql.replace(sql.find("enterface"),std::string ("enterface").size(),cfg.ent);   
        if (simula==1){sql="/usr/bin/netstat -i | grep enp | awk '{print $4}'|tr -d '\n'";};
  PutLog(sql); 
  FILE *p = popen(sql.c_str(),"r");   
  for (size_t count; (count = fread(buf, 1, sizeof(buf), p));){
      s += string(buf, buf + count);  
  };
  PutLog("Текущий трафик:");
  PutLog(s);
  pclose(p);
  curtfaff=atoi(s.c_str());
  PutLog("--читаю предыдущие значения трафика и метки времени /etc/shapercpp.traf");
      ifstream F1("/etc/shapercpp.traf"); // открыли файл для чтения
      char buff[50];
      F1.getline(buff,50);old_curtfaff=atoi(buff);
      F1.getline(buff,50);old_current_time=atoi(buff);
      F1.getline(buff,50);delta_old=atoi(buff);
      F1.getline(buff,50);current_percent=atof(buff);
      PutLog("--- предыдущее время запуска old_current_time:");      
      PutLog(from_int(old_current_time));
      PutLog("--- предыдущий трафик old_curtfaff:");      
      PutLog(from_int(old_curtfaff));      
      PutLog("--- предыдущая delta:");      
      PutLog(from_int(delta_old));            
      F1.close();
      current_time=time(NULL);
      PutLog("--- текущее время current_time:");      
      PutLog(from_int(current_time));
      PutLog("--- текущий трафик curtfaff:");      
      PutLog(from_int(curtfaff));      
  PutLog("---с предыдущего запуска прошло sec:");
    sec=current_time-old_current_time;    
    PutLog(from_int(sec));
    delta = (curtfaff - old_curtfaff)/sec/1000/1000*8,0;
            if (simula==1){
                srand (time(NULL));
                delta=rand()%1400;                
            };
    PutLog("--- трафик за секунду delta:");    
    PutLog(from_int(delta));
    PutLog("--- ускорение delta_a:");    
    delta_a=abs(delta-delta_old);
    PutLog(from_int(delta_a));
   PutLog("--переопределяю коэффициенты lg:");
    if (abs(delta_a)>1){
        lg=floor(log(delta_a))*10;
    } else {
        lg=10;
    };        
    if (lg>50){lg=50;};
    PutLog(from_float(lg));
    
    kofdec=lg/2;     
    kofinc=lg/2;   
    kofdec=kofdec/100;
    kofinc=kofinc/100;
    kofmin=kofmin/100;    
    PutLog("--kofdec:");PutLog(from_float(kofdec));
    PutLog("--kofinc:");PutLog(from_float(kofinc));
    PutLog("--kofmin:");PutLog(from_float(kofmin));
    PutLog("--- cfg.maxw:");
    PutLog(from_int(cfg.maxw));
    PutLog("--- cfg.minw:");
    PutLog(from_int(cfg.minw));        
    if (delta>cfg.maxw){
            current_percent = current_percent-current_percent*kofdec;        
            if (current_percent<kofmin){current_percent=kofmin;};
            if (current_percent>1){current_percent=current_percent*kofdec;};
            PutLog("--уменьшаю скорость current_percent:");
       };
    if (delta<=cfg.minw){
            current_percent = current_percent+current_percent*kofinc;
            //если вдруг ширина канала стала нормальной, а процент адаптации очень низкий, то ставим стразу kofmin,
            if (current_percent<kofmin){current_percent=kofmin;PutLog("--устанавливаю current_percent на 0.3");};
            if (current_percent>(cfg.maxperc/100)){current_percent=cfg.maxperc/100;};        
            PutLog("--увеличиваю скорость current_percent:");            
        };    
    PutLog(from_float(current_percent));    
    PutLog("--записываю текущий трафик,время,ускорение и процент в файл /etc/shapercpp.traf");
    ofstream F2;
    F2.open("/etc/shapercpp.traf");
    F2<< curtfaff;F2<< "\n";
    F2<< current_time;F2<< "\n";
    F2<< delta;F2<< "\n";
    F2<< current_percent;F2<< "\n";
    F2.close();             
    PutLog("--записываю данные для заббикса в файл /etc/zabbix.info");
    
    string tt;
    F2.open("/etc/zabbix.info");    
    tt="persent:"+from_int(current_percent*100);
    F2<< tt;F2<< "\n";
    tt="max:"+from_int(cfg.maxw);
    F2<< tt;F2<< "\n";
    tt="min:"+from_int(cfg.minw);
    F2<< tt;F2<< "\n";
    tt="delta:"+from_int(delta);
    F2<< tt;F2<< "\n";
    tt="log:"+from_float(lg);
    F2<< tt;F2<< "\n";    
    F2.close();             
    
};
tars *GetTarifsFromNoc(){
  PutLog("--извлекаю текущие настройки тарифов из НОС");   
 //если не в "автономке", то берем "свеженькие" данные по тарифам с самого НОС, иначе - читаем из файла
    if (noc!=1){        
        sql ="SELECT count(*) as cnt FROM lanbshapbytarifs where blibase='zxc'";        
        sql.replace(sql.find("zxc"),std::string("zxc").size(),from_int(cfg.blibaseid));   
        //sql.replace(sql.find("enterface"),std::string (cfg.ent).size(),cfg.ent);   
        PutLog(sql);   
        if (mysql_query(connectionNOC, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query\n");exit(1);};
        result=mysql_store_result(connectionNOC);
        if(result == NULL) {fprintf(stderr,"Error: can't get the result description\n");exit(1);};
        int flag=0;
        int cnttar=0;
        while ((row = mysql_fetch_row(result)) != NULL){flag=1;cnttar=atoi(row[0]);};
        if (flag=0){fprintf(stderr,"Что-то не то.. не смог сделать выборку по тарифам из НОС!\n");exit(1);  };
        PutLog("Количество тарифов:");   
        PutLog(from_int(cnttar));   
        //выделяем память под массив тарифов
        tars *noctar=new tars[cnttar];      
        sql ="SELECT * FROM lanbshapbytarifs where blibase='zxc'";        
        sql.replace(sql.find("zxc"),std::string("zxc").size(),from_int(cfg.blibaseid));   
        //sql.replace(sql.find("enterface"),std::string (cfg.ent).size(),cfg.ent);   
        PutLog(sql);   
        if (mysql_query(connectionNOC, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query\n");exit(1);};
        result=mysql_store_result(connectionNOC);
        if(result == NULL) {fprintf(stderr,"Error: can't get the result description\n");exit(1);};        
        while ((row = mysql_fetch_row(result)) != NULL){            
            noctar[counttar].fixshape=atoi(row[5]);
            noctar[counttar].onlytar=atoi(row[10]);
            noctar[counttar].tar_id=atoi(row[2]);
            noctar[counttar].tar_name=row[3];
            noctar[counttar].used=atoi(row[9]);         
            noctar[counttar].maxspeed=atoi(row[6]);         
            counttar++;
        };        
        if (flag=0){fprintf(stderr,"Что-то не то.. не смог сделать выборку по тарифам из НОС!\n");exit(1);  };
        PutLog("--занес тарифы в динамический массив");
        for (int i = 0; i < counttar; i++) {        
          if (debug==1){
            printf("----Тариф: %s \n",std::string(noctar[i].tar_name).c_str());              
            printf("-----Уменьшение скорости: %i \n",noctar[i].onlytar);              
            printf("-----Увеличение скорости: %i \n",noctar[i].fixshape);              
            printf("-----MaxSpeed: %i \n",noctar[i].maxspeed);              
            printf("-----tar_id: %i \n",noctar[i].tar_id);                          
          };          
        };  
     return noctar;         
    } else {
        
    };   
};
users *GetCurUsers(){
 PutLog("--Заполняю массив Users..");     
 
 sql="SELECT count(*) as cnt FROM staff st LEFT JOIN vgroups vg ON vg.vg_id = st.vg_id WHERE vg.uid in (select uid from usergroups_staff where group_id in (!ferma_sql)) AND vg.id in (!agents) AND st.segment_id in (!segment) and vg.blocked<>10";
 sql.replace(sql.find("!agents"),std::string("!agents").size(),cfg.agents);   
 sql.replace(sql.find("!ferma_sql"),std::string("!ferma_sql").size(),cfg.ferma);   
 sql.replace(sql.find("!segment"),std::string("!segment").size(),cfg.segments);   
 PutLog(sql);  
 if (mysql_query(connectionBilling, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query %s\n",mysql_error(connectionBilling));exit(1);};
 result=mysql_store_result(connectionBilling);
 if(result == NULL) {fprintf(stderr,"Error: can't get the result description\n");exit(1);};
 int flag=0;
 int cntusers=0;
 while ((row = mysql_fetch_row(result)) != NULL){flag=1;cntusers=atoi(row[0]);};
 if (flag=0){fprintf(stderr,"Что-то не то.. не смог сделать выборку учетных записей из биллинга! %s\n",mysql_error(connectionBilling));exit(1);  };

 sql="SELECT vg.vg_id as zvg_id,INET_NTOA(st.segment) AS ip,vg.current_shape AS c_shape,vg.tar_id AS tar,vg.login AS login FROM staff st LEFT JOIN vgroups vg ON vg.vg_id = st.vg_id  WHERE vg.uid in (select uid from usergroups_staff where group_id in (!ferma_sql)) AND vg.id in (!agents) AND st.segment_id in (!segment) and vg.blocked<>10";
 sql.replace(sql.find("!agents"),std::string("!agents").size(),cfg.agents);   
 sql.replace(sql.find("!ferma_sql"),std::string("!ferma_sql").size(),cfg.ferma);   
 sql.replace(sql.find("!segment"),std::string("!segment").size(),cfg.segments);   
 PutLog(sql);  
 if (mysql_query(connectionBilling, sql.c_str()) != 0){fprintf(stderr,"Error: can't execute SQL-query %s\n",mysql_error(connectionBilling));exit(1);};
 result=mysql_store_result(connectionBilling);
 if(result == NULL) {fprintf(stderr,"Error: can't get the result description %s\n",mysql_error(connectionBilling));exit(1);};

 PutLog("Количество учёток:");   
 PutLog(from_int(cntusers));   
 //выделяем память под массив пользователей
 int zx=0;flag=1;
 users *busers=new users[cntusers];      
 while ((row = mysql_fetch_row(result)) != NULL){
    flag=1; 
    busers[zx].vg_id=atoi(row[0]);    
    busers[zx].ip=row[1];    
    busers[zx].b_shape=atoi(row[2]);    
    busers[zx].tar_id=atoi(row[3]);    
    busers[zx].login=row[4];        
    busers[zx].pipe_in=0;
    busers[zx].pipe_out=0;
    busers[zx].real_speed_in=0;
    busers[zx].real_speed_out=0;    
    busers[zx].fixshape=-1;    
    busers[zx].onlytar=-1;    
            //заполняем данные по тарифам
            for (int i = 0; i < counttar; i++) {                  
               if (gtars[i].tar_id==busers[zx].tar_id){
                busers[zx].fixshape=gtars[i].fixshape;    
                busers[zx].onlytar=gtars[i].onlytar;                       
               };
            };
    zx++;
 };
 if (flag=0){fprintf(stderr,"Что-то не то.. не смог сделать выборку учетных записей из биллинга! %s\n",mysql_error(connectionBilling));exit(1);  };
       PutLog("--занес учетки в динамический массив");
       if (debug==1){
        for (int i = 0; i < cntusers; i++) {                  
            printf("----Учетка: %s \n",std::string(busers[i].login).c_str());              
            printf("-----ip: %s \n",std::string(busers[i].ip).c_str());              
            printf("-----Скорость по биллингу: %i \n",busers[i].b_shape);              
            printf("-----tar_id: %i \n",busers[i].tar_id);              
            printf("-----vg_id: %i \n",busers[i].vg_id);    
          };  
        };  
 countusers=cntusers;       
 return busers;
};
int GetCurPipes(){
  int res;    
  string ss,ip,pipe,mb;  
  ifstream F,Fz;
  char buff[50];  
  //добавляю фиктивную трубу, для отлова ошибки..
  system("/sbin/ipfw pipe 1 config bw 1");
  system("/sbin/ipfw pipe table 1 add 127.0.0.99 1");
  system("/sbin/ipfw pipe table 2 add 127.0.0.99 1");
  
  PutLog("--Читаю текущие ipfw table 1 list..");  
  res=system("/sbin/ipfw table 1 list > /tmp/table1.lst");
  if (res>0){
    PutLog("--ахтунг. не получилось считать ipfw table 1 list. Выходим! Код ошибки: "+from_int(res));    
    exit(res);
  };
   //читаем файл который получился..    
    PutLog("--читаю /tmp/table1.lst");    
    F.open("/tmp/table1.lst");
    while (!F.eof()){
        F.getline(buff,50);
        if (F.eof()==false){
            ss=std::string(buff);               
            ip=ss.substr(0,ss.find("/"));
            pipe=ss.substr(ss.find("/")+3,ss.length()-ss.find("/")+3);
            //заполняем массив gusers;
            for (int i = 0; i < countusers; i++) {       
                if (gusers[i].ip==ip){
                   gusers[i].pipe_in=atoi(pipe.c_str());
                };
            };  
        };   
    };    
    F.close();  
    F.clear();
    PutLog("--прочитал");    
  PutLog("--Читаю текущие ipfw table 2 list..");  
  res=system("/sbin/ipfw table 2 list > /tmp/table2.lst");
  if (res>0){
    PutLog("--ахтунг. не получилось считать ipfw table 2 list. Выходим! Код ошибки: "+from_int(res));    
    exit(res);
  };
   //читаем файл который получился..    
    F.open("/tmp/table2.lst");
    while (!F.eof()){
        F.getline(buff,50);
        if (F.eof()==false){
            ss=std::string(buff);        
            ip=ss.substr(0,ss.find("/"));
            pipe=ss.substr(ss.find("/")+3,ss.length()-ss.find("/")+3);
            //заполняем массив gusers;
            for (int i = 0; i < countusers; i++) {       
                if (gusers[i].ip==ip){
                   gusers[i].pipe_out=atoi(pipe.c_str());
                };
            };  
        };   
    };    
    F.close();  
    F.clear();
  PutLog("--Читаю текущие Pipes..");    
  res=system("/sbin/ipfw pipe list | grep :> /tmp/pipe.lst");
  if (res>0){
    PutLog("--ахтунг. не получилось считать pipe. Выходим! Код ошибки: "+from_int(res));    
    exit(res);
  };
   //читаем файл который получился..    
    F.open("/tmp/pipe.lst");  
    while (!F.eof()){
        F.getline(buff,50);
        if (F.eof()==false){
            ss=std::string(buff);
            ss=trim(ss);
            pipe=ss.substr(0,ss.find(":"));            
            mb=ss.substr(ss.find(":")+1,ss.find(".")-ss.find(":")-1);
            //заполняем массив gusers;
            int flag=0;
            for (int i = 0; i < countusers; i++) {       
                if (gusers[i].pipe_in==atoi(pipe.c_str())){
                     gusers[i].real_speed_in=atoi(mb.c_str());
                     gusers[i].real_speed_in=gusers[i].real_speed_in*1000000;
                     flag=1;
                };
                if (gusers[i].pipe_out==atoi(pipe.c_str())){
                     gusers[i].real_speed_out=atoi(mb.c_str());
                     gusers[i].real_speed_out=gusers[i].real_speed_out*1000000;
                     flag=1;
                };                
            };  
            if (flag==0){
                PutLog("---удаляю лишний Pipe!");                
                //ищу соответствие IP, Этому pipe
                    Fz.open("/tmp/table2.lst",ios::in);                                        
                    string pipe_f;
                    string rn="";
                    while (!Fz.eof()){
                        Fz.getline(buff,50);
                        if (Fz.eof()==false){
                            ss=std::string(buff);        
                            ip=ss.substr(0,ss.find("/"));
                            pipe_f=ss.substr(ss.find("/")+3,ss.length()-ss.find("/")+3);
                            if (pipe==pipe_f){
                                PutLog(pipe);
                                PutLog(ip);                                
                                rn="/sbin/ipfw table 1 delete "+ip;
                                PutLog(rn);
                                system(rn.c_str());
                                rn="/sbin/ipfw table 2 delete "+ip;
                                PutLog(rn);
                                system(rn.c_str());
                            };  
                        };   
                    };    
                     rn="/sbin/ipfw pipe delete "+pipe;
                     PutLog(rn);
                     system(rn.c_str());                     
                    Fz.close();                                  
                    Fz.clear();
            };

        };
    };    
    F.close();
//выводим результат если в дебюге    
       if (debug==1){
        PutLog("--Итоговый массив учеток:");      
        for (int i = 0; i < countusers; i++) {                  
            printf("----Учетка: %s \n",std::string(gusers[i].login).c_str());              
            printf("-----ip: %s \n",std::string(gusers[i].ip).c_str());              
            printf("-----Скорость по биллингу: %i \n",gusers[i].b_shape);              
            printf("-----tar_id: %i \n",gusers[i].tar_id);              
            printf("-----vg_id: %i \n",gusers[i].vg_id);              
            printf("-----pipe_in: %i \n",gusers[i].pipe_in);              
            printf("-----pipe_out: %i \n",gusers[i].pipe_out);              
            printf("-----real_speed_in: %i \n",gusers[i].real_speed_in);              
            printf("-----real_speed_out: %i \n",gusers[i].real_speed_out);              
            printf("-----Коф.fix_up: %i \n",gusers[i].fixshape);              
            printf("-----Коф.fix_down: %i \n",gusers[i].onlytar);              
          };  
        };  
    
};
int GetPipeFromIp(string ip){
 string p1,p2;
 int pz1,pz2,pz3,ppp;
 pz1=ip.find(".");
 pz2=ip.find(".",pz1+1);
 pz3=ip.find(".",pz2+1);
 p1=ip.substr(pz2+1,pz3-pz2-1);
 p2=ip.substr(pz3+1,ip.length()-pz3);
 ppp=(atoi(p1.c_str())-token)*256+atoi(p2.c_str());
 return ppp;
};
int AddPipes(){
    PutLog("--создаем Pipe для учеток!");                 
    int pipe_new=0;
    string rn;
    for (int i = 0; i < countusers; i++) {       
     if ((gusers[i].pipe_out==0) or (gusers[i].pipe_in==0)){                
        PutLog("---"+gusers[i].login+"/"+gusers[i].ip);                                 
        pipe_new=GetPipeFromIp(gusers[i].ip);
        gusers[i].pipe_in=pipe_new;
        gusers[i].pipe_out=pipe_new+10000;
        gusers[i].real_speed_in=gusers[i].b_shape*1000;
        gusers[i].real_speed_out=gusers[i].b_shape*1000;
        rn="/sbin/ipfw table 1 add "+gusers[i].ip+" "+from_int(pipe_new);
        PutLog(rn);
        system(rn.c_str());                     
        rn="/sbin/ipfw table 2 add "+gusers[i].ip+" "+from_int(pipe_new+10000);
        PutLog(rn);
        system(rn.c_str());                     
        rn="/sbin/ipfw pipe "+from_int(pipe_new)+" config bw "+from_int(gusers[i].b_shape*1000);
        PutLog(rn);
        system(rn.c_str());                     
        rn="/sbin/ipfw pipe "+from_int(pipe_new+10000)+" config bw "+from_int(gusers[i].b_shape*1000);
        PutLog(rn);
        system(rn.c_str());                     
     };
    };    
};
int SetSpeed(){
    PutLog("--устанавливаю новую скорость");
    string rn;
    int sp_in,sp_out;
    for (int i = 0; i < countusers; i++) {       
        //если уменьшаем скорость, то
        if (current_percent<1) {
            if (gusers[i].onlytar==0){
                 //если скорость не максимальная, то уменьшаем...
                 PutLog("---Снижаем! текущая реальная скорость:"+from_int(gusers[i].real_speed_in)+", макс. для этого тарифа: "+from_int(gusers[i].b_shape*10*cfg.maxperc));
                 if (gusers[i].real_speed_in>gusers[i].b_shape*100*3){
                    sp_in=gusers[i].real_speed_in*current_percent;
                    if (sp_in<gusers[i].b_shape*100*3){sp_in=gusers[i].b_shape*100*3;};
                    sp_out=gusers[i].real_speed_out*current_percent;
                    if (sp_out<gusers[i].b_shape*100*3){sp_out=gusers[i].b_shape*100*3;};                    
                    PutLog("---"+gusers[i].login+", fixshape:"+from_int(gusers[i].fixshape)+";onlytar="+from_int(gusers[i].onlytar));
                    rn="/sbin/ipfw pipe "+from_int(gusers[i].pipe_in)+" config bw "+from_int(sp_in);
                    system(rn.c_str());                     
                    PutLog(rn+" по шейперу:"+from_int(gusers[i].b_shape*100)+", текущая:"+from_int(sp_in)+", коэф.:"+from_float(current_percent));
                    rn="/sbin/ipfw pipe "+from_int(gusers[i].pipe_out)+" config bw "+from_int(sp_out);
                    system(rn.c_str());                     
                    PutLog(rn+" по шейперу:"+from_int(gusers[i].b_shape*100)+", текущая:"+from_int(sp_out)+", коэф.:"+from_float(current_percent));
                 } else {
                    PutLog("---у абонента "+gusers[i].login+" скорость не трогаем, и так минимальная");                       
                 };                
            } else {
                 PutLog("---у абонента "+gusers[i].login+" тариф с фиксированной скоростью (вниз не уменьшаем)");  
             };
        };       
        //если увеличиваем скорость, то
        if (current_percent>1) {
            //если можем у этого абонента повышать скороcсть
             if (gusers[i].fixshape==0){
                 //если скорость не максимальная, то увеличиваем...
                 PutLog("---Увеличиваем! текущая реальная скорость:"+from_int(gusers[i].real_speed_in)+", макс. для этого тарифа: "+from_int(gusers[i].b_shape*10*cfg.maxperc));
                 if (gusers[i].real_speed_in<(gusers[i].b_shape*cfg.maxperc*10)){
                    sp_in=gusers[i].real_speed_in*current_percent;
                    if (sp_in>gusers[i].b_shape*cfg.maxperc*10){sp_in=gusers[i].b_shape*cfg.maxperc*10;};
                    sp_out=gusers[i].real_speed_out*current_percent;
                    if (sp_out>gusers[i].b_shape*cfg.maxperc*10){sp_out=gusers[i].b_shape*cfg.maxperc*10;};                    
                    PutLog("---"+gusers[i].login+", fixshape:"+from_int(gusers[i].fixshape)+";onlytar="+from_int(gusers[i].onlytar));
                    rn="/sbin/ipfw pipe "+from_int(gusers[i].pipe_in)+" config bw "+from_int(sp_in);
                    system(rn.c_str());                     
                    PutLog(rn+" по шейперу:"+from_int(gusers[i].b_shape)+", текущая:"+from_int(sp_in)+", коэф.:"+from_float(current_percent)+";b_shape="+from_int(gusers[i].b_shape)+";max_pers="+from_int(cfg.maxperc));
                    rn="/sbin/ipfw pipe "+from_int(gusers[i].pipe_out)+" config bw "+from_int(sp_out);
                    system(rn.c_str());                     
                    PutLog(rn+" по шейперу:"+from_int(gusers[i].b_shape)+", текущая:"+from_int(sp_out)+", коэф.:"+from_float(current_percent)+";b_shape="+from_int(gusers[i].b_shape)+";max_pers="+from_int(cfg.maxperc));
                 } else {
                    PutLog("---у абонента "+gusers[i].login+" скорость не трогаем, и так максимальная: real_speed="+from_int(gusers[i].real_speed_in)+",максимальная скорость:"+from_int(gusers[i].b_shape*cfg.maxperc*10));                       
                 };
             } else {
                 PutLog("---у абонента "+gusers[i].login+" тариф с фиксированной скоростью (вверх не увеличиваем)");  
             };
            
        };
    };    
};
int main(int argc, char** argv) {           
    GetCommandLine(argc,argv); //обрабатываем аргументы коммандной строки
    GetCommonConfig();  //получаем настройки шейпера, устанавливаем соединение с БД НОС и биллинга    
    GetCurrentSpeed();  //расчитываем коэффициенты увеличения/уменьшения скорости
    gtars=GetTarifsFromNoc(); //получаем список тарифов и их параметров из НОС    
    //counttar - количество тарифов,gtars - массив тарифов
    gusers=GetCurUsers();     //получаем список абонентов текущего агента,подразделения
    //countusers - количество учеток, gusers - массив абонентов
    GetCurPipes();      //получаем текущий список пайпов у ipfw
    AddPipes(); // добавляем пайпы если не хватает..
    SetSpeed(); // изменяем текущие скорости на пайпах..
    return 0;
}

Комментарии:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.