Как использовать один сокет OpenSSL DTLS-сервер со многими клиентами?
Я пытаюсь добавить DTLS на мой прослушивающий сервер UDP с неблокирующим сокетом; Однако в настоящее время у меня возникают некоторые проблемы с пониманием того, как оптимально использовать функции DTLS OpenSSL. Я рассмотрел почти каждый пример, который мог найти в Интернете, но большинство работает только с одним клиентом (s_server.c/s_client.c) или имеет дело с конфигурацией 1-нитка на клиент, которая, насколько я понимаю, неэффективна для многих (10k~) одновременных подключений. Это приводит меня к нескольким вопросам, связанным с созданием сервера DTLS, который использует только один неблокирующий сокет.
Один из основных вопросов: когда данные из буфера сокетов помещаются в буфер чтения BIO из буфера сокетов? Глядя на источник для функции dtlsv1_listen, я нахожу следующее:
n = BIO_read(rbio, buf, SSL3_RT_MAX_PLAIN_LENGTH);
Что приводит меня к мысли, что rbio уже содержит буфер сокета; однако единственная настройка rbio до этого находится в строке:
rbio = SSL_get_rbio(s); //s is the SSL struct of the server
который просто копирует биографию из структуры сервера, но все еще не отвечает, как извлекается исходный буфер сокета. Очевидно, что здесь я что-то упускаю, но я в растерянности. Я предполагаю, что какой-либо механизм отвечает за то, что это будет своего рода оболочка для функции, подобной recvfrom(). И хотя я могу найти вызов функции recfrom() в функции dgram_read() bss_dgram.c, я не могу найти никаких вызовов самой функции dgram_read().
Причина этого вопроса в том, что я хотел бы определить момент до того, как буфер чтения BIO заполнится, чтобы я мог выполнить некоторые базовые проверки IP-заголовков (например, баланс белого / запретного списка или балансировка рабочего потока), пока пакет все еще находится в сокете. Очередь а не в слушателя читается БИО.
Другой вопрос: какой минимальный объем данных мне нужно хранить для каждого клиента, чтобы поддерживать шифрованное чтение / запись после завершения рукопожатия? Я знаю, что идентификаторы соединений хранятся в структуре SSL, и для неблокирующих сокетов, скорее всего, нужна небезупречная биография для чтения и записи. В настоящее время я думаю следующее:
Struct ClientDTLS { //per client struct
SSL *ssl; //client specific ssl struct
BIO *bio; //client specific bio for read
addr_in addr; //client addr
}
Это слишком много или недостаточно данных? Должен ли я выполнить какое-либо сокращение источника для полей ssl_st или bio_st? Моя текущая цель - сохранить списки этих структур в рабочих потоках с балансировкой нагрузки, что приводит меня к моему последнему вопросу:
При работе с рабочими потоками с балансировкой нагрузки, когда будет наилучшее время для расшифровки данных пакета? Когда пакет поступает в мой основной поток слушателя, я должен отправить его в рабочий поток в зашифрованном виде (на основе незашифрованного идентификатора потока в пользовательском заголовке пакета) или немедленно расшифровать его, а затем отправить в рабочий поток на основе идентификатора в незашифрованных данных. Я полагаю, что первое может привести к потенциальной атаке ddos, которая может быть нацелена на конкретные рабочие потоки, но я предполагаю, что постоянная расшифровка моего основного потока прослушивания может вызвать проблемы с перегрузкой.
Я прошу прощения, если какой-либо из моих вопросов наивен, поскольку OpenSSL для меня немного нов, но я благодарю вас за любую помощь, которую вы можете оказать.