Сервер icecast может использоваться не только для организации вещания новых сетевых медиапотоков, но и для ретрансляции уже существующих. Источник исходного потока при этом может являться распределенной структурой других icecast-подобных серверов, в которых для распределения нагрузки на головном сервере может использоваться простой http-редирект (код 302) на дополнительные узлы.
Хотя relay-функциональность icecast и позволяет разбирать этот код и реагировать на него соответствующим образом, работает это не всегда.
Можно столкнуться со следующей ситуацией: головной source-сервер перегружен и выдает редиректы на дополнительные серверы, при проверке браузером все корректно, но наш icecast-ретранслятор их будто “не замечает” и выдает клиентам ошибку 404. В логах нашего icecast’а при этом можно увидеть следующие записи:
[2015-09-25 10:58:40] INFO slave/start_relay_stream Starting relayed source at mountpoint "/<mountname>" [2015-09-25 10:58:40] INFO slave/open_relay_connection connecting to <main.source>:80 [2015-09-25 10:58:40] INFO slave/open_relay_connection redirect received HTTP://<fallback.source>
После этого клиенту выдается ошибка 404 и более ничего содержательного в лог не попадает. Так в чем же дело?
В исходном коде icecast можно найти следующие строки:
ICECAST_LOG_INFO("redirect received %s", uri); if (strncmp (uri, "http://", 7) != 0) break;
Так выясняется, что если полученная ссылка из 302-го редиректа не начинается на “http://” (в НИЖНЕМ регистре!), то наш icecast с ней не будет делать вообще ничего и сделает вид, что никакого редиректа не было. А как видно из лога, наш источник рассылает редиректы, начинающиеся на HTTP:// в верхнем регистре.
Очевидно, надо научить icecast не обращать внимание на разницу регистров в протоколе. Это можно сделать разными способами, оптимальность и красота которых зависит от качества вашего владения кунг-фу Си. Можно, например, сделать как-то так:
--- icecast-2.4.2/src/slave.c 2015-04-08 11:06:13.000000000 +0300 +++ icecast-2.4.2-mod/src/slave.c 2015-09-25 10:55:29.495738535 +0300 @@ -238,13 +238,19 @@ if (strcmp (httpp_getvar (parser, HTTPP_VAR_ERROR_CODE), "302") == 0) { /* better retry the connection again but with different details */ - const char *uri, *mountpoint; - int len; + const char *uri, *mountpoint, *proc = "http://"; + int i, len; uri = httpp_getvar (parser, "location"); + ICECAST_LOG_INFO("redirect received %s", uri); - if (strncmp (uri, "http://", 7) != 0) - break; + for (i = 0; i < 7 && uri[i]; i++) { + if ((tolower(uri[i]) - tolower(proc[i])) != 0) { + i = 10; + break; + } + } + if (i == 10) break; uri += 7; mountpoint = strchr (uri, '/'); free (mount);
Пересобираем, подключаемся, смотрим лог:
[2015-09-25 11:08:40] INFO slave/start_relay_stream Starting relayed source at mountpoint "/<mountname>" [2015-09-25 11:08:40] INFO slave/open_relay_connection connecting to <main.source>:80 [2015-09-25 11:08:40] INFO slave/open_relay_connection redirect received HTTP://<fallback.source> [2015-09-25 11:08:40] INFO slave/open_relay_connection connecting to <fallback.source>:80 [2015-09-25 11:08:40] WARN format/format_get_type Unsupported or legacy stream type: "audio/mpeg". Falling back to generic minimal handler for best effort. [2015-09-25 11:08:40] INFO source/source_main listener count on /<mountname> now 1
И все работает.