Показаны сообщения с ярлыком coding. Показать все сообщения
Показаны сообщения с ярлыком coding. Показать все сообщения

суббота, 21 апреля 2012 г.

fork vs pthread

Попытка построить ядро моего диплома, включающего сбор ip, tcp и http заголовков с отправкой их в mysql для последующего анализа на базе одного процесса провалилась - инсерт сильно дольше приёма очередного пакета при большом трафике, в БД каша получается.
Попытался делать так - форкать отдельный процесс под отправку данных в БД и передавать ему обработанный пакет через пайп - тот же эффект.
Стал одним процессом собирать запросы в shared memory,  дочерним зеркалировать участок памяти и из зеркала слать. Синхронизацию делал через posix semaphores. Что получил - при большом трафике тот процесс, что загребает трафик, постоянно заходит в свою критическую зону, а отсылающий процесс просто висит в ожидании, отжирая целое ядро.

Уже было отчаился, но решил переписать с тредами - и, о диво! Оно заработало!!!
Механика такая: создаём 2 треда - для сбора трафика и для отправки.
Первый в pcap_loop callout раздирает пакет и формирует VALUE список, добавляя его в своей критической секции в шаренный через анонимный mmap участок.
Второй тред в своей критикал цепляет содержимое вышеуказанного участка в свой буфер и после выхода из критикала спокойно инсертит одним запросом. Сегодня вечером выкатил на продакшн, было около 3 тыс. инсертов в секунду.
Вот сам код, непричёсанный ещё, правда:
 https://github.com/speedcorezombie/pget/blob/master/pget.c

понедельник, 19 марта 2012 г.

libpcap, продолжение

Дополнил хэлло экстракцией http пакета, теперь вывод выглядит так:
Packet captured
IP header lengh:  20
Packet size:  60
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            SYN


Packet captured
IP header lengh:  20
Packet size:  60
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 52987
Flags:            SYN ACK


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            ACK


Packet captured
IP header lengh:  20
Packet size:  372
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            ACK
GET / HTTP/1.1
Host: speedcorezombie.net
User-Agent: Mozilla/5.0 (X11; Linux i686; rv:10.0.1) Gecko/20100101 Firefox/10.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Connection: keep-alive



Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 52987
Flags:            ACK


Packet captured
IP header lengh:  20
Packet size:  323
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 52987
Flags:            ACK
HTTP/1.1 200 OK
Date: Mon, 19 Mar 2012 19:26:14 GMT
Server: Apache/2.2.15 (CentOS)
Last-Modified: Sun, 18 Mar 2012 20:52:54 GMT
ETag: "6e653-6-4bb8aa02c9580"
Accept-Ranges: bytes
Content-Length: 6
Connection: close
Content-Type: text/html; charset=UTF-8

hello


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            ACK


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            ACK FYN


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 52987
Flags:            ACK FYN


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      52987
Destination port: 80
Flags:            ACK


Packet captured
IP header lengh:  20
Packet size:  52
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 52987
Flags:            ACK
Теперь осталось решить, какие поля http заголовка заграббить в базу )

libpcap hello

Надо граббить ip,tcp и http хэдеры для последующего анализа. Пока вот для теста наваял этакий хелловорлд:

#include <pcap/pcap.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main() {

        char* device;                    // Sniffing device
        char errbuf[PCAP_ERRBUF_SIZE];   // Error message buffer
        pcap_t* handle;                  // Session handle
        struct bpf_program fp;           // The compiled filter expression
        char filter_exp[] = "port 80";   // The filter expression
        bpf_u_int32 mask;                // The netmask of our sniffing device
        bpf_u_int32 net;                 // The IP of our sniffing device
        struct pcap_pkthdr header;       // The header that pcap gives us
        const u_char* packet;            // The actual packet
        struct iphdr* ipheader = NULL;   // Pointer to the IP header
        struct tcphdr* tcpheader = NULL; // Pointer to the TCP header
        device = NULL;
        memset(errbuf, 0, PCAP_ERRBUF_SIZE);
        int count;

        device = pcap_lookupdev(errbuf);
        printf("Device: %s\n", device);
        printf("filter: %s\n", filter_exp);
        if (pcap_lookupnet(device, &net, &mask, errbuf) == -1) {
                fprintf(stderr, "Can't get netmask for device %s\n", device);
                net = 0;
                mask = 0;
        }

        handle = pcap_open_live(device, 2048, 0, 512, errbuf);

        if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
                fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
                exit(1);
        }

        if (pcap_setfilter(handle, &fp) == -1) {
                fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
                exit(1);
        }
        count = 100;
        while (count) {
                // Try to get packet. If capture fail - try next.
                if ( (packet = pcap_next(handle, &header)) == NULL) {
                        fprintf(stderr, "ERROR: Error getting the packet\n", errbuf);
                        continue;
                } else
                        fprintf(stderr, "Packet captured\n");

                // Extract IP header
                ipheader = (struct iphdr *)(packet + 14);
                printf("IP header lengh:  %d\n", ipheader->ihl);
                printf("Source IP:        %s\n", inet_ntoa( *(struct in_addr *) &ipheader->saddr));
                printf("Destination IP:   %s\n", inet_ntoa( *(struct in_addr *) &ipheader->daddr));
                // Extract TCP header
                tcpheader = (struct tcphdr *)(packet + 14 + ipheader->ihl * 4);
                printf("Source port:      %d\n", ntohs(tcpheader->source));
                printf("Destination port: %d\n", ntohs(tcpheader->dest));
                printf("Flags:            ");
                if (tcpheader->syn)
                        printf("SYN ");
                if (tcpheader->ack)
                        printf("ACK ");
                if (tcpheader->fin)
                        printf("FYN ");
                printf("\n");
                printf("\n");

        }
        pcap_close(handle);
        return 0;
}

Вывод такой (запрос простой html странички):
# ./pcap
Device: wlan0
filter: port 80
ERROR: Error getting the packet
ERROR: Error getting the packet
ERROR: Error getting the packet
ERROR: Error getting the packet
ERROR: Error getting the packet
Packet captured
IP header lengh:  5
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      53375
Destination port: 80
Flags:            SYN

Packet captured
IP header lengh:  5
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 53375
Flags:            SYN ACK

Packet captured
IP header lengh:  5
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      53375
Destination port: 80
Flags:            ACK

Packet captured
IP header lengh:  5
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      53375
Destination port: 80
Flags:            ACK

Packet captured
IP header lengh:  5
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 53375
Flags:            ACK

Packet captured
IP header lengh:  5
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 53375
Flags:            ACK

Packet captured
IP header lengh:  5
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      53375
Destination port: 80
Flags:            ACK

Packet captured
IP header lengh:  5
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 53375
Flags:            ACK FYN

Packet captured
IP header lengh:  5
Source IP:        192.168.10.108
Destination IP:   178.21.10.7
Source port:      53375
Destination port: 80
Flags:            ACK FYN

Packet captured
IP header lengh:  5
Source IP:        178.21.10.7
Destination IP:   192.168.10.108
Source port:      80
Destination port: 53375
Flags:            ACK

ERROR: Error getting the packet

среда, 30 ноября 2011 г.

Быдлокод на мсдн

Сейчас на мсдн наткнулся на такой вот ахтунг:


   DWORD count = 0;
   printf("Printing Key BLOB for verification \n");
   for(count=0; count < dwBlobLen;)
   {
      printf("%02x",pbKeyBlob[count]);
      count ++;
   }
пруфлинк
На этом ресурсе всё такое уё6Nщное?

воскресенье, 23 мая 2010 г.

Считать число. Продолжение темы.

Ранее я уже писал, как проще всего считать число из стандартного ввода и строки. Теперь возникла необходимость считать некую белиберду из строки, в которой может быть неск. элементов, пробелы и всякий мусор. Но главное, если там не чисто целое число, а, например, 4.aa, то чтобы не была считана 4, отбросив остальное. И можно было бы определить, что тут косяк.

Сделал функцию, которой передаём поток (как при чтении числа из строки),
из которого читаем:

string getElement(istringstream* strStream) {
    char ch;
    string* input = new string;
    input->assign("");
    // Пропуск пробелов
    do {
        strStream->read(&ch, 1);
    } while (ch == ' ');
        // Считывание минуса, если он есть
        if (ch == '-') {
            input->append(1, ch);
            strStream->read(&ch, 1);
        }
        // Поэлементное считывание числа
        do {
            if ((ch >= '0') && (ch <= '9')) {
                if (strStream->good()) {
                    input->append(1, ch);
                    strStream->read(&ch, 1);
                } else
                    break;
            } else if (!strStream->good() || (ch == ' ') || (ch == '\n') || (ch == '\0'))
                break;
            else {
                return "error";
            }
        } while (1);
    return *input;
}
А потом полученную строку пытаемся загнать в переменную.
Отрывок из кода, где такая штука используется:

testString->assign("");
getline(inputfile, *testString);
testStream = new istringstream(*testString);
element = new istringstream(getElement(testStream));
delete testStream;

if ((*element >> s) && (s > 0) && (s <= 127)) {
          outputfile << s << endl;
          delete element;
}

вторник, 11 мая 2010 г.

Ротация бекапов в fsbackup

fsbackup - замечательная штука, но сохраняет токо последний бекап. Немного переделал скрипт, заменив сохранение старого бекапа на ротацию до 10 бекапов:

# Удаление старых бекапов
    print "Remove old backup\n";
        foreach $cur_dir ($ftp->ls()) {
            if ($cur_dir =~ /\.9$/) {
                $ftp->delete($cur_dir);
             }
        }
    # Ротация бекапов
        print "Backup rotating:\n";
        for ($i = 8; $i > 0; --$i) {
            $j = $i + 1;
            foreach $cur_dir ($ftp->ls()) {
                $name = $new_name = $cur_dir;
                if ($name =~ /\.$i$/) {
                    $new_name =~ s/\.$i$/\.$j/;
                    print "$name -> $new_name\n";
                    $ftp->rename($name, $new_name) or die "Can't rename $name\n";
                }
            }
        }
        foreach $cur_dir ($ftp->ls()) {
            $name = $new_name = $cur_dir;
                if ($name =~ /\.\w{2,5}$/) {
                    $new_name = $name.".1";
                    print "$name -> $new_name\n";
                    $ftp->rename($name, $new_name) or die "Can't rename $name\n";
                }
        }

пятница, 5 марта 2010 г.

Qt: "Hello world!"

Наконец-то дошли руки до Кьюти ))
Очень приятная штука, надо заметить. Пожалуй, курсовую по Теории языков программирования буду на Qt ваять.

понедельник, 27 апреля 2009 г.

Реализация возможности повторного прогона.

Иногда требуется сделать в софтине возможность повторного прогона. Вот как это делаю я:

do {

// .... код ....

cout << "Ввести 1 для повтора или 2 для выхода и нажать Enter: ";
do {
a = cin.get();
if ((a == '1') || (a == '2'))
break;
else
cout << "Неверный ввод, повторите: " << endl;
// очистка буфера
cin.clear();
cin.ignore(numeric_limits::max(),'\n');
} while (true);
// очистка буфера, обусловлена тем, что нужно избежать
// попадания '\n', вызванного нажатием на Enter, в cin
cin.clear();
cin.ignore(numeric_limits::max(),'\n');
} while (a == '1');
Возможно, не самый изящный способ, но зато довольно простой.

суббота, 11 апреля 2009 г.

Нерекурсивная быстрая сортировка на C++

Всё, наконец-то алгоритм работает как надо )
Ввиду того, что в инете нет сорса нормальной нерекурсивной функции бысторой сортировки на C++ (зато есть куча нерабочих или слишком хитровытраханных), выкладываю свой, вдруг кому-нибудь да пригодится.

void Quick(int arr[], int n)
{
int base, left, right, i, j;
base = left = right = i = j = 0;
Stack stack;

stack.Push(n - 1);
stack.Push(0);
do { // while (stack.GetSP() != NULL)
left = stack.Pop();
right = stack.Pop();
if (((right - left) == 1) && (arr[left] > arr[right]))
swap(arr[left], arr[right]);
else {

base = arr[(left + right) / 2];
i = left;
j = right;
// цикл продолжается, пока индексы i и j не сойдутся
do { // while (i > j)
// пока i-ый элемент не превысит опорный
while ((base > arr[i]))
++i;
// пока j-ый элемент не окажется меньше опорного
while (arr[j] > base)
--j;
if (i <= j)
swap(arr[i++], arr[j--]);
} while (i <= j);
}
if (left < j) {
stack.Push(j);
stack.Push(left);
}
if (i < right) {
stack.Push(right);
stack.Push(i);
}
} while (stack.GetSP() != NULL);
}


Со стеком, я думаю, всё понятно. В конце концов, если человек не понимает, как реализовать Push и Pop, то он ещё не дорос до Хоара и эта писанина для него тёмный лес.

Быстрая сортировка. Нерекурсивная.

Уже третий день мучаюсь с сабжем.
Вроде наконец написал рабочий алгоритм (для C++), когда на одном из тестов сортировка улетела в вечный цикл - оказалось, что при определённом расположении элементов в стек закидываются, а затем снимаются, одни и те же индексы...

воскресенье, 5 апреля 2009 г.

Ввод строки неизвестного размера

Юзер что-то вводит. Надо это грамотно считать, выделив под строку необходимое кол-во памяти.
Делаем так:
string* str;
str = new string;
std::getline(cin, *str);

Преобразование строки в число в C++

С проверкой разобрались, а как правильнее поступить, когда есть строка и её надо конвертировать в число? Конечно, можно по-старинке при помощи atoi(), но это.. некрасиво, что ли..
Гораздо интереснее рассмотреть строку как поток и загнать в переменную, как в предыдущем посту ))

Итак, есть строка str, в ней что-то лежит:


string* str;
............
// что-то происходит со строкой..
............
istringstream myStream(*str);
if (myStream >> t)
cout << "Ok" << endl;
else
cout << "Not ok" << endl;


istringstream описан в sstream. Намёк ясен?
нэймспэйс - std

Проверка "число-не число" на C++

Мне известно несколько способов проверки - что ввёл юзер, число или какое-нибудь нехорошее слово.
Можно загонять ввод в строку, а потом посимвольно проверять isdigit'ом, можно попытаться преобразовать строку в число и смотреть, что получится. Но для себя я выбрал такой способ: взять и загнать без лишних слов ввод в числовую переменную, а дальше по обстановке:



int t;
if (cin >> t)
cout << "Ok" << endl;
else
cout << "Not ok" << endl;



Просто и элегантно.
Работает так:
Введено число, умещающееся в свой тип: Ok.
Введена конструкция из цифр (хотя бы одна лидирующая) и свякой фигни, напр. 111aaa - в переменную считается число до первой "не цифры", в данном случае 111, остальное останется в буфере.
Введено что-то иное - Not ok.

четверг, 2 апреля 2009 г.

Ожидание нажатия на Enter в C++

При переписывании старых паскалевских лаб на C++ столкнулся с проблемой:
в некоторых случаях нужно что-то показать юзеру и подождать, пока он не нажмёт Enter.
В паскале это решалось функцией ReadLn(), а в Си обычно в этих случаях юзают getchar() (в C++ cin.get()).
Но. Если до этого момента осуществлялся ввод, то, если он не был полностью считан, оставшиеся в буфере символы будут схаваны getchar'ом и, соответственно, пользователя ждать никто не станет. Выходов несколько - либо считать несколько раз (что некрасиво), либо вычистить буфер и считать один раз.
Нашёл реализацию второго способа (ссылка) и доработал его слегка. Вот что получилось:

#include <iostream>
#include <limits>
using namespace std;

void MyPause()
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n'); // Очистка буфера
cout << "Нажмите Enter для продолжения..." << endl;
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}

пятница, 18 июля 2008 г.

Мой будущий почтовый клиент

Параллельно с изучением Postfix начал писать в образовательных целях одну штуку. Это будет простой почтовый клиент, к которому я со временем прикручу гуй на Qt, а впоследствии поддержку шифрования. Таким образом, я укреплю свои знания в области сокетов и smtp протокола, а также окунусь в ООП.

Пишу на C++, пытаясь максимально придерживаться парадигмы ООП.
Пока готов набросок класса Socket, кот. будет использоваться для соединения с сервером и готов класс Message, объект которого будет письмом.

четверг, 12 июня 2008 г.

C++: Конструкторы и инициализация

В одной статье нашёл важные правила, связанные с инициализациеё переменных:

Здесь нужно соблюдать следующие 2 неформальных, но очень важных правила.
  1. Все переменные-члены класса должны быть инициализированы в конструкторе, подчеркиваем, все! Если их даже 1000 и инициализация большинства по смыслу не нужна, все равно их все надо тупо выписать в том порядке, в котором они описаны в интерфейсе класса, и присвоить им некоторые начальные значения.
  2. Инициализацию всегда следует выполнять не внутри тела конструктора, а в списке инициализации.
Список инициализации располагается между заголовком конструктора, после которого ставится двоеточие, и телом конструктора, которое начинается с открывающей фигурной скобки.

пятница, 6 июня 2008 г.

ООП: второй подход

Ну вот, наконец-то дошли руки до Си пэ пэ.
Первый штурм не привёл к результатам - пытался с ходу переписать свою курсовую с объектного паскаля на C++, но подошёл не с того конца.
Моя софтина оперировала с матрицами, математика была написана на чистом паскале, а весь гламур (гуй) на объектнике (читай - в среде делфи). Я решил всю математику, кот. по сути работает с многомерными массивами, засунуть в класс. Туда же, думал, засуну саму матрицу.
Проблема в том, что я ещё не знаю, как сделать так, чтобы объектом этого класса был динамический многомерный массив, с кот. можно было бы обращаться как привык с обычными.
Поэтому решил забить на пока на всё и начать с cpp'ного hello world ) :

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
if (argc <= 1)
cout << "Hello, world!\n";
else
cout << "Hello, " << argv[1] << "!\n";
return 0;
}

Вот что получилось:
accessd@deck:~/code/cpp> vim hello.cpp
accessd@deck:~/code/cpp> g++ hello.cpp -o hello.bin
accessd@deck:~/code/cpp> ./hello.bin Stas
Hello, Stas!
accessd@deck:~/code/cpp> ./hello.bin
Hello, world!


Начало положено )
Вот ещё бы выкроить время на программирование модулей.. уже год пытаюсь написать модуль для моргания клавиатурных светодиодов. Может, после сессии..

суббота, 31 мая 2008 г.