Guest User

Untitled

a guest
Apr 10th, 2023
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.01 KB | Source Code | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5.  
  6. // Размер статического буфера под вывод результата консольных команд
  7. #define BUFFER_SIZE 4096
  8. // Размер буфера под текстовое представление чисел
  9. // так как atoi и иже с ними в стандартной библиотеке принимают только сишные строки
  10. // заканчивающиеся на термининирующий ноль, поэтому будем копировать чтоб сделать сишные строки
  11. // можно конечно редактировать исходный буфер, но без необходимости лучше не заниматься преждевременной оптимизацией
  12. #define ATOI_BUFFER 256
  13. // Количество секунд между проверками
  14. #define SLEEP_TIME_SECONDS 30
  15.  
  16. // Объявление функции, чтоб можно было их расположить в любом порядке, так я хочу их разместить после main функции
  17. int executeCommand(char *command, char *buffer, int bufferSize, size_t *dataSize);
  18. void checkNetLimit(char *buffer, size_t bufferSize);
  19. void checkLineLimit(char *buffer, size_t bufferSize);
  20. long int toNumber(char *buffer, size_t length);
  21. void getNextLine(char *buffer, size_t bufferSize, size_t *lineStart, size_t *lineLength);
  22. void skipNewLineSymbols(char *buffer, size_t bufferSize, size_t *pos);
  23. void findFirstNewLineSymbol(char *buffer, size_t bufferSize, size_t *pos);
  24. int isNewLine(char symbol);
  25.  
  26. // Отсюда стартует программа
  27. int main()
  28. {
  29.     // Наш буфер куда будем писать вывод консольных команд
  30.     // выделяем на байт больше так как последний байт занулим
  31.     // и не прийдется потом из размера буфера вычитать единицу чтоб не затереть этот терминирующий ноль
  32.     char buf[BUFFER_SIZE + 1];
  33.     // В конец на всякий случай пишем терминирующий ноль чтоб в худшем случае у нас получилась сишная строка
  34.     buf[BUFFER_SIZE] = 0;
  35.     // Переменная для размера текстовой строки
  36.     // size_t это числовая переменная хранящая размер данных
  37.     // это unsigned int но в 32 битных приложениях занимает 32 бита, на 64 битных соответственно 64 бита
  38.     size_t dataSize = 0;
  39.     // Переменная для результата выполнения функций, успех если 0 или номер ошибки
  40.     int res = 0;
  41.  
  42.    system ("sh servMesg.sh");
  43.    // Бесконечно крутимся в цикле
  44.    // тут можно конечно добавить проверку на прерывание выполнения из консоли по ctrl+c и корректно завершиться
  45.    // но это если уже весь код понятен, а так это лишнее для такого простого кода
  46.     while (1) {
  47.         // Выполняем командную строку и получаем вывод
  48.         res = executeCommand("netstat |grep '7776 ESTABLISHED' | awk '{print $2}'", buf, BUFFER_SIZE, &dataSize);
  49.         // Если есть вывод и он не пустой то проверяем лимиты
  50.         if (res == 0 && dataSize) {
  51.             checkNetLimit(buf, dataSize);
  52.         }
  53.  
  54.         // Также получаем вывод и если не пустой то проверяем количество строк
  55.         res = executeCommand("netstat |grep '7776 ESTABLISHED' | wc -l", buf, BUFFER_SIZE, &dataSize);
  56.         if (res == 0 && dataSize) {
  57.             checkLineLimit(buf, dataSize);
  58.         }
  59.  
  60.         // Засыпаем на некоторое время
  61.         sleep(SLEEP_TIME_SECONDS);
  62.     }
  63.     return 0;
  64. }
  65.  
  66. // Выполнение консольной команды из переменной command, и запись текстового вывода в массив по указателю buffer
  67. // учитывая максимальный размер текстового буфера хранящего в переменной bufferSize
  68. // размер текста запишем в dataSize
  69. int executeCommand(char *command, char *buffer, int bufferSize, size_t *dataSize)
  70. {
  71.     // Результат выполнения этой функции, ноль нет ошибок, остальное номер ошибки
  72.     int result = 0;
  73.     // Переменная содержащая указатель на пайп, иницилиазируем его нашей командой на выполнение
  74.     FILE *pipe = popen(command, "r");
  75.     // Обнуляем размер результата вывода на случай если будет ошибка
  76.     *dataSize = 0;
  77.  
  78.     // Если не удалось открыть пайп то пишем ошибку и прерываем выполнение
  79.     // в си не приветствуется множественное использование return
  80.     // но в данном случае нам не надо очищать ресурсы
  81.     if (pipe == NULL) {
  82.         fprintf(stderr, "Error open pipe");
  83.         return 1;
  84.     }
  85.  
  86.     // Количество всех прочитанных байтов
  87.     size_t bytesRead = 0;
  88.     // Количество байтов прочитанных fread
  89.     size_t bytes = 0;
  90.     // Читаем из пайпа пока есть данные
  91.     do {
  92.         // Читаем данные в буфер
  93.         // для того чтоб данные дописывались к предыдущим сдвигаем указатель buffer на количество уже записанных байт(bytesRead)
  94.         // также не забываем уменьшить размер буфера на количество записанных байт
  95.         bytes = fread(buffer + bytesRead, 1, bufferSize - bytesRead, pipe);
  96.         // Если есть прочитанные байты то добавляем их к общему количеству прочитанных байт
  97.         if (bytes) {
  98.             bytesRead += bytes;
  99.         // Если нет прочитанных байт то это либо конец данных либо ошибка
  100.         } else {
  101.             // Проверим есть ли ошибка и если есть напишем в вывод ошибок
  102.             int errorCode = ferror(pipe);
  103.             if (errorCode) {
  104.                 result = 1;
  105.                 fprintf(stderr, "Error read pipe: %d", errorCode);
  106.             }
  107.         }
  108.     } while (bytes);
  109.  
  110.     // Записываем количество прочитанных данных в внешнюю переменную
  111.     *dataSize = bytesRead;
  112.     // Не забываем очистить ресурсы и закрываем пайп.
  113.     pclose(pipe);
  114.  
  115.     return result;
  116. }
  117.  
  118. // Функция проверки сетевых лимитов
  119. void checkNetLimit(char *buffer, size_t bufferSize)
  120. {
  121.     // Начало строки, в данном случае это не указатель а смещение (offset) в байтах относительно начала текстового буфера
  122.     size_t lineStart = 0;
  123.     // Длина строки
  124.     size_t lineLength = 0;
  125.     // Числовой результат который попытаемся получить из строки
  126.     long int number = 0;
  127.  
  128.     // Выполняем цикл пока есть непустые строки
  129.     do {
  130.         // Получаем начало и длину строки из текстового буфера
  131.         getNextLine(buffer, bufferSize, &lineStart, &lineLength);
  132.         // Если есть строка и она не пустая
  133.         if (lineLength) {
  134.             // Конвертим строку в число
  135.             number = toNumber(buffer + lineStart, lineLength);
  136.             if (number > 50000) {
  137.                 system ("sh alarm.sh");
  138.                 printf ("количество пакетов превышено\n");
  139.                 printf ("%ld\n", number);
  140.             }
  141.         }
  142.     } while (lineLength);
  143. }
  144.  
  145. // Функция проверки количества строк
  146. void checkLineLimit(char *buffer, size_t bufferSize)
  147. {
  148.     // Начало строки, в данном случае это не указатель а смещение (offset) в байтах относительно начала текстового буфера
  149.     size_t lineStart = 0;
  150.     // Длина строки
  151.     size_t lineLength = 0;
  152.     // Числовой результат который попытаемся получить из строки
  153.     long int number = 0;
  154.  
  155.     // Получаем начало и длину строки из текстового буфера
  156.     getNextLine(buffer, bufferSize, &lineStart, &lineLength);
  157.     // Если есть строка и она не пустая
  158.     if (lineLength) {
  159.         // Конвертим строку в число
  160.         number = toNumber(buffer + lineStart, lineLength);
  161.         if (number < 2) {
  162.             system ("sh alarm1.sh");
  163.             printf ("Строк меньше двух\n");
  164.         }
  165.         printf ("%ld\n", number);
  166.     }
  167. }
  168.  
  169. // Функция конвентирования строки в число
  170. long int toNumber(char *buffer, size_t length)
  171. {
  172.     // Буфер где будем хранить строку с числом плюс байт на терминирующий ноль
  173.     char atoibuf[ATOI_BUFFER + 1];
  174.     // Обнуляем последний байт
  175.     atoibuf[ATOI_BUFFER] = 0;
  176.  
  177.     // Если входная строка больше буфера то обрезаем длину и пишем в лог ошибок
  178.     if (length > ATOI_BUFFER) {
  179.         fprintf(stderr, "Error atoi buffer too small: %d, required size: %ld", ATOI_BUFFER, length);
  180.         length = ATOI_BUFFER;
  181.     }
  182.  
  183.     // Копируем строку из буфера вывода в наш временный буфер
  184.     memcpy(atoibuf, buffer, length);
  185.     // Не забываем в конец добавить терминирующий ноль для функции atol
  186.     atoibuf[length] = 0;
  187.  
  188.     // Конвентируем строку в число и возращаем это число
  189.     return atol(atoibuf);
  190. }
  191.  
  192. // Функция для получения смещения в байтах следущей строки и её длину
  193. void getNextLine(char *buffer, size_t bufferSize, size_t *lineStart, size_t *lineLength)
  194. {
  195.     // Получаем смещение новой строки, для этого к предыдущему смещению добавляем длину
  196.     // в результате получим смещение сразу на следующий байт после предыдущей строки
  197.     size_t newLineStart = *lineStart + *lineLength;
  198.     // Длина новой строки пока что обнулим переменную
  199.     size_t newLineLength = 0;
  200.     // Переменная для указания получилось ли найти новую строку или нет, ноль значит больше нет строк, обнулим её
  201.     int validString = 0;
  202.  
  203.     // Проверяем что смещение на новую строку меньше размера буфера, иное означает что буфер закончился и новых строк нет
  204.     if (newLineStart < bufferSize) {
  205.         // Для начала вызовем функцию которая сдвинет смещение к первому символу не являющемуся переводом строки
  206.         // так мы пропустим байты означающие перевод строки и получим новое смещение указывающее на начало строки
  207.         skipNewLineSymbols(buffer, bufferSize, &newLineStart);
  208.         // Снова проверяем не закончился ли буфер и то что смещение указывает не на байт новой строки
  209.         if ((newLineStart < bufferSize) && !isNewLine(buffer[newLineStart])) {
  210.             // Создаем переменную смещения указывающую на конец строки, в данном случае это просто следующий байт
  211.             size_t newLineEnd = newLineStart + 1;
  212.             // Теперь вызываем функцию которая сдвинет смещения конца строки на первый попавшийся символ новой строки
  213.             // Также если в конце буфера нет байта перевода строки то смещение будет указывать на первый байт за пределом буфера
  214.             findFirstNewLineSymbol(buffer, bufferSize, &newLineEnd);
  215.             // Получаем длину новой строки просто вычитая из смещения конца строки смещение начала строки
  216.             newLineLength = newLineEnd - newLineStart;
  217.             // В переменную успеха поиска строки записываем 1 как факт что мы нашли строку
  218.             validString = 1;
  219.         }
  220.     }
  221.  
  222.     // Если мы нашли строку то устанавливаем новые значения смещения и длины строки
  223.     // иначе просто обнуляем длину
  224.     if (validString) {
  225.         *lineStart = newLineStart;
  226.         *lineLength = newLineLength;
  227.     } else {
  228.         *lineStart = 0;
  229.         *lineLength = 0;
  230.     }
  231. }
  232.  
  233. // Функция которая сдвигает смещение пока оно не будет указывать на символ новой строки
  234. // либо будет указывать на следующий байт за пределами буфера
  235. // функцию просто сдвинет смещение пропуская все смещения указывающие на символ новой строки
  236. void skipNewLineSymbols(char *buffer, size_t bufferSize, size_t *pos)
  237. {
  238.     // Крутим цикл пока не вылезем за пределы буфера
  239.     while (*pos < bufferSize) {
  240.         // Если смещение указывает на символ новой строки то пропускаем его увеличивая смещение на еденицу
  241.         // иначе прерываем цикл так как нашли начало новой строки
  242.         if (isNewLine(buffer[*pos])) {
  243.             (*pos)++;
  244.         } else {
  245.             break;
  246.         }
  247.     }
  248. }
  249.  
  250. // Функция которая сдвигает смещение пока оно будет указывать не на символ новой строки
  251. // либо будет указывать на следующий байт за пределами буфера
  252. // функция просто сдвинет указатель к символу новой строки
  253. void findFirstNewLineSymbol(char *buffer, size_t bufferSize, size_t *pos)
  254. {
  255.     // Крутим цикл пока не вылезем за пределы буфера
  256.     while (*pos < bufferSize) {
  257.         // Если смещение не указывает на символ новой строки то увеличиваем смещение на еденицу
  258.         // иначе прерываем цикл так как нашли конец строки
  259.         if (!isNewLine(buffer[*pos])) {
  260.             (*pos)++;
  261.         } else {
  262.             break;
  263.         }
  264.     }
  265. }
  266.  
  267. // Функция проверки символа на символ новой строки
  268. // в качестве новой строки будет проверять как символ новой строки \n так и символ возарата каретки \r
  269. // так как типичная ситуация когда перевод строки это последовательность символов \r\n
  270. // учитываем что это работает только для ascii и utf-8 и то что оба символа в utf-8 занимают один байт
  271. // с кириллицей данное не будет работать в utf-8
  272. int isNewLine(char symbol)
  273. {
  274.     return (symbol == '\r' || symbol == '\n');
  275. }
Advertisement
Add Comment
Please, Sign In to add comment