суббота, 17 марта 2018 г.

Черный список

У нас есть телефонная станция на базе Asterisk расположена в датацентре. Всякий кому не лень пытается "взломать" пароль SIP и подключится на халяву к нашей телефонной сети. Меня это беспокоит.
Статистика неумолима. до 80млн. запросов в год на подбор пароля. Это невероятно много запросов, которые захламляют лог. Такого чтобы кто-то подключился и получил телефонных услуг на халяву, не замечено.

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

Виртуальная сеть для контроллера

Настраивал операционную систему. Выбирал таймеры для реализации виртуальной сети.
Нашел несколько полезных вещей, стал применять.

Таймеры на Windows. Необходимым оказалось подкручивать параметр мультимедиа таймера
Использую функцию timeBeginPeriod(wTimerRes);
Я заметил, что на нескольких разных компьютерах под управлением Windows 7 по разному ведет себя процесс отладки. Он то бежит как угорелый, символы быстро пробегают по экрану, то тормозит. Даже на одном компьютере я получил результат, что  после перезагрузки, он стал медленнее обрабатывать протокол. Замерил параметр задержки, оказалось, что вместо usleep(1000)=1мс, квант времени равняется 15мс. А у меня протокол должен работать с разрешением времени минимум 5мс. При 15мс, виртуальная сеть тормозит и вызывает таймауты в работе виртуальных устройств.

Таймеры pthread. Моя сеть должна работать на Windows, Linux и на моей операционке. Основа виртуальной сети - очередь таймерных объектов -- блоков памяти, которые доставляются в строго определенное время.
Исследовал разрешение таймеров.
clock_getres(CLOCK_MONOTONIC) возвращает 370 микросекунд. На разных процессорах эта цифра разная, но меньше 1мс.
clock_getres(CLOCK_REALTIME) возвращает 15.6мс.
Измерять время надо монотонным, иначе цифры округляются до безобразных величин.

Монотонный таймер оказался не очень то монотонным, на этом потерял целый день на отладку работы виртуальной сети и планировщика.
Чтобы сделать из монотонного таймера действительно монотонный применил такой ход:
(uint64_t)(tv_nsec + tv_sec*1000000000); Иногда в tv_nsec встречаются любые числа, неожиданные. Монотонным таймер становится только после такой операции.

 timestamp = osKernelSysTick();
 while ((uint32_t)(timestamp - tr->wait.timestamp) < tr->wait.timeout) {
     interval.tv_nsec = (tr->wait.timeout - (uint32_t)(timestamp - tr->wait.timestamp));
     clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, &diff);
     timestamp = osKernelSysTick();
 }

Применил такой вариант ожидания. Ожидание применяется перед получением пакета данных.

Основа сети - асинхронная очередь, куда любой тред может засунуть пакет данных, но планировщик один - один читатель много писателей. Реализация асинхронной очереди на атомарных операциях, в моем случае делается на операциях атомарного доступа к памяти.

void osAsyncQueuePut(osAsyncQueue_t* queue, void* data)
{
    List_t* tr = g_slice_alloc(sizeof(List_t));
    tr->data = data;
    volatile void** ptr = (volatile void**)&queue->tail;
    do {
        tr->next = atomic_pointer_get(ptr);
        atomic_mb();
    } while(!atomic_pointer_compare_and_exchange(ptr, tr->next, tr));
}

Эта операция добавляет элемент в список - вместо верхнего элемента. Список снимается в одно движение со стороны планировщика:
queue->head = atomic_pointer_exchange(&queue->tail, NULL);
Перед разбором список надо перевернуть, чтобы получить нормальный хронологический порядок.

Вот и все искусство.