mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix(tci): рекордер линейного выхода — память под потолком, файл только в своём каталоге
Два дефекта уровня P1 в LINE_OUT_RECORDER_*. Авторизации в протоколе нет
(§3.1), bind наружу разрешён — значит «сколько стоит одна строка из сети»
это вопрос живучести процесса, а не аккуратности.
1. Неограниченное выделение памяти. CmdRecorder проверял только ValidRx
(номер в потолке), а конструктор выделял буфер целиком: 300 с × 48 кГц
× 2 канала × int16 = 57.6 МБ на команду, приёмников 1+MAX_SLICES=7, то
есть 403 МБ семью строками. У мёртвого приёмника Feed не зовут — значит
срок записи никто не проверял; уход клиента рекордеры не трогал вовсе;
DropDeadRxStreams бежит только на rfDevice/rfConnected и смене карты
слайсов, в покое не срабатывает. Память жила до остановки сервера.
Лечение тремя замками:
- память набирается кусками по секунде, START не стоит ни байта;
куски не перевыделяются (никакого realloc в DSP-потоке) и склеиваются
один раз в Take — уже после того, как рекордер вынут из таблицы;
- общий бюджет TCI_RECORD_MAX_BYTES (128 МБ) на все рекордеры сразу,
спрашивается на каждый кусок; отказ не рушит запись, набранное
остаётся сохраняемым;
- освобождение по трём событиям: START требует живого приёмника
(RxActive, ответ receiver is not running), тик сервера подметает
истёкшие окна по часам (SweepRecorders — окно закрывается от START
и без единого блока звука), уход клиента забирает его записи
(DropClientRecorders; рекордер живёт на приёмнике, но платит за него
тот, кто нажал START).
2. Перезапись произвольного файла. Путь из сети уходил в fmCreate почти
как пришёл — вместе с '..' и абсолютными путями. Теперь TCIRecordPath
берёт из строки ТОЛЬКО имя файла, каталог — настроенный tci.record_dir
(пусто = <каталог конфигурации>/records). Каталог из просьбы
отбрасывается молча: полный путь на сервере клиенту всё равно
бесполезен, файл ложится не на его машину. Имя валидируется (пусто,
'.', '..', управляющие, ':', длиннее 120, расширение не .wav →
bad file name); после ExtractFileName выйти за каталог нечем. Файл
создаётся эксклюзивно (TCICreateNewFile: O_EXCL|O_NOFOLLOW на Unix,
CREATE_NEW на Windows) — ни перезаписи, ни симлинка, без окна между
FileExists и созданием; клиенту заранее file exists.
Попутно: MainForm.ApplyTCISettings собирал TTCISettings по полям с
чистого листа — новое поле RecordDir обнулялось бы при каждом применении
вкладки CAT. В uses TCIStreams Windows стоит первым намеренно: иначе его
TCriticalSection перекрыл бы SyncObjs (та же грабля, что в DX-кластере).
Стенд 189/189 (было 169): 11 проверок имени файла (/etc/passwd.wav,
../../.., D|\rec\a.wav), бюджет (START не выделяет, растёт кусками,
потолок, отказ не рушит запись, срок истекает без Feed), существующий WAV
не перезаписывается, START на мёртвом приёмнике и с чужим номером, и
сквозная проверка в части E — клиент стартует запись, набирает память
живым звуком через WDSP, рвёт TCP, бюджет возвращается к нулю. Без фиксов
новые проверки краснеют. GUI (--ws=qt6) и демон зелёные.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -58,6 +58,17 @@ const
|
||||
TCI_TX_BUFFERING_MIN = 50;
|
||||
TCI_TX_BUFFERING_MAX = 500;
|
||||
TCI_RECORD_MAX_SEC = 300; // потолок записи линейного выхода
|
||||
// ★Общий потолок памяти ВСЕХ рекордеров сразу. Приёмников у нас
|
||||
// 1 + MAX_SLICES, и предельные 300 с на каждом — это 57.6 МБ × 7 ≈ 403 МБ,
|
||||
// которые неавторизованный клиент выпрашивал бы семью строками. Бюджет
|
||||
// общий на адаптер, спрашивается при выделении КАЖДОГО куска (см.
|
||||
// TTCIRecorder): 128 МБ — это две полных записи предельной длины, больше
|
||||
// одновременно не нужно никому.
|
||||
TCI_RECORD_MAX_BYTES = Int64(128) * 1024 * 1024;
|
||||
// Кусок кольца записи — секунда звука (48000 × 2 канала × int16 = 192 КБ).
|
||||
// Выделяем их по мере набора: команда START больше не стоит ни байта, а
|
||||
// молчащий или мёртвый приёмник не стоит ничего вовсе.
|
||||
TCI_RECORD_CHUNK_SEC = 1;
|
||||
|
||||
TCI_VOL_MIN_DB = -60; TCI_VOL_MAX_DB = 0;
|
||||
TCI_SQL_MIN_DB = -140; TCI_SQL_MAX_DB = 0;
|
||||
|
||||
Reference in New Issue
Block a user