Сервер 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
И все работает.