Помните неровную отладку | Проблема с блокировкой Mosquitto при подключении к EMQ через TLS

За последние два дня при отладке встроенной системной среды Linux, после включения системы, при подключении Mosquitto к MQTT-серверу (EMQ) через tls, MQTT-соединение всегда блокировалось при его создании.Сейчас буду записывать отладку. процесс и шаги по решению проблемы.

Давайте сначала поговорим о среде разработки и отладки:

  • Аппаратная платформа : EXP imx.6ull.
  • Версия ядра : 4.1.15.
  • rootfs : создан на основе buildroot
  • комар : 2.0.11
  • опенссл : 1.1.1
  • Сервер MQTT : EMQ, поддерживающий службу TLS.

проблема внешнего вида

После загрузки системы Linux и появления приглашения на вход в оболочку вызываются mosquitto_connect и EMQ для установления соединения на основе TLS. Вызов mosquitto_connect блокируется примерно на 90 секунд, прежде чем вызов функции вернется и будет сообщено об ошибке. После этого mosquitto запустит механизм повторного подключения и снова подключится к серверу EMQ, и соединение будет успешным. В это время, если запрос на подключение к EMQ будет повторно инициирован, mosquitto_connect не будет блокироваться.

Некоторые причины первоначальных сомнений:

  1. После запуска системы перед инициализацией сети вызывается mosquitto_connect, и соединение с EMQ может не состояться. Попробуйте метод тестирования: улучшите процесс инициализации сети и оптимизируйте время вызова mosquitto_connect.После тестирования он недействителен.
  2. Если вы подозреваете, что возникла проблема с сервером EMQ, попробуйте метод проверки: используйте другие устройства для проверки инициирования подключения TLS к тому же EMQ, и проблем не будет.
  3. При запуске не синхронизируется системное время (1970-01-01 08:00:00).После подключения сети служба ntpd синхронизирует сетевое время с локальным, поэтому соединение mqtt будет заблокировано.После подумав об этом, если это проблема с системным временем, mosquitto_connect должен вернуть сообщение об ошибке, указывающее, что сертификат проверки TLS недействителен, а не блокируется.
  4. Я подозревал, что другие части приложения мешают процессу вызова mosquitto_connect. Я использовал mosquitto_pub для публикации сообщений непосредственно в EMQ и обнаружил то же явление.

После вышеописанных раундов подозрений и тестирования отладка зашла в тупик.Я был немного подавлен.Подумав об этом, я использовал козырную карту: самый глупый и эффективный метод: вставить логи отладки в процесс выполнения mosquitto_connect . На самом деле, иногда, казалось бы, самый глупый метод является наиболее эффективным методом отладки.Пока направление правильное, стоит потратить некоторое время и энергию.

Шаги отладки

Следуйте процессу вызова mosquitto_connect, добавьте журналы и определите место блокировки. Вот небольшой совет по отладке: начните с магистрали, а затем детали . То есть сначала добавьте журналы в ключевые места на основном пути, которые нужны для отладки, а затем компилировать и отлаживать.Вы можете определить общее расположение проблемы, затем снова добавить журналы в подпроцесс, скомпилировать и отладить.Таким образом, рекурсивно шаг за шагом, вы можете быстро найти проблема . Применив этот метод, я наконец определил, что проблема блокировки mosquitto_connect следующая:

SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_client_method());

Позвольте мне кратко представить SSL_CTX_new, который в основном представляет собой блок управления, созданный openssl для связи TLS. Чтобы подтвердить проблему, я написал тестовую программу, чтобы еще раз подтвердить, вызвала ли эта функция проблему. код показан ниже:

#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/err.h>
#include <openssl/ui.h>
#include <openssl/ssl.h>
 
void ssl_test(void)
{
    
    
    printf("ssl_test:TP0.\n");
    SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_client_method());
 
    (void)ssl_ctx;
    printf("ssl_test:TP1.\n");
}

Процедура очень проста: нужно просто подтвердить, является ли виновником SSL_CTX_new. После включения Linux немедленно выполняется тестовая функция. Сначала печатается «ssl_test:TP0». Примерно через 90 секунд печатается «ssl_test:TP1». Местоположение проблемы подтверждается.

проблема найдена

Если вы новичок в механизме SSL/TLS или понимаете только процесс взаимодействия SSL/TLS, немного сложно анализировать принцип реализации SSL_CTX_new.Я принадлежу к этому типу людей, поэтому отладка еще раз в беде.

Когда я был в растерянности, я обнаружил интересный феномен: я обнаружил, что терминалу нужно напечатать только одну строку:

random: nonblocking pool is initialized

SSL_CTX_new вернется. После нескольких тестов подтвердите последовательность между ними. Видно, что существует связь между инициализацией случайного значения и блокировкой SSL_CTX_new. После этого отладка прошла относительно гладко, было действительно сложно найти выход из гор и рек, а в другой деревне нас ждало блестящее будущее .

Изучив информацию, я обнаружил, что существуют следующие основные решения для случайного: неблокирующий пул инициализируется :

1. Быстрая инициализация неблокирующего пула случайных чисел Linux.

2. Случайный: неблокирующий пул инициализируется, но приглашение не выводится при включении компьютера, что фактически не решает проблему.

3. Быстрая инициализация неблокирующего пула случайных чисел Linux.

После анализа 1 и 3 в основном соответствуют явлению этой проблемы: можно определить, что существует проблема с случайным драйвером ядра версии 4.1.15, из-за которой случайная инициализация замедляется (90 с), когда система запускается, и во время инициализации используется SSL_CTX_new.random, которому необходимо дождаться завершения случайной инициализации, прежде чем он сможет продолжить выполнение, вызывая блокировку SSL_CTX_new и, в конечном итоге, блокировку mosquitto_connect.

Решать проблему

Измените код случайного драйвера ядра: driver/char/random.c , найдите функцию add_interrupt_randomness и измените следующий код:

Исходный код:

 if ((fast_pool->count < 64) &&
            !time_after(now, fast_pool->last + HZ))
        return;

Модифицированный код:

 if ((fast_pool->count < 64) &&
         !time_after(now, fast_pool->last + HZ) &&
         nonblocking_pool.initialized)
     return;

Примечание: Версия ядра в этой статье — 4.1.15. После проверки кода ядра было обнаружено, что в более новой версии ядра ошибка устранена!

Скомпилируйте, замените ядро ​​и после тестирования проблема решена!

постскриптум

Оглядываясь назад на процесс решения этой проблемы, я не знаю, заметили ли вы это. Вначале явление проблемы и первопричину проблемы можно описать как «восемь полюсов невозможно поразить » . раз я чувствую, что проблема вот-вот будет решена, в конце концов, это все равно. Чувство потери и тревоги будет становиться все сильнее и сильнее . На самом деле, проанализировав процесс решения проблемы постфактум, нетрудно найти ключ к решению проблемы : сначала сохраняйте спокойствие и определите направление, затем используйте научные методы, чтобы неуклонно двигаться вперед, верьте в себя, и, наконец, проблема в конечном итоге будет решена. Это всего лишь вопрос времени .

Guess you like

Origin blog.csdn.net/linux_embedded/article/details/126100266