TCP-стек XBox 360 не отвечает на TCP Zero Window Probes с 0-байтовой полезной нагрузкой

Я экспериментирую с Android-приложением, которое передает музыку через UPnP на XBox. Потоковая передача по большей части работает, но довольно часто через минуту или две потоковая передача останавливается, особенно когда в сети есть другая активность. Этого никогда не происходит при потоковой передаче на другие устройства, отличные от XBox. Я подтвердил такое поведение с помощью ряда различных серверных приложений UPnP.

Проанализировав множество трассировок Wireshark, я нашел основную причину. Кажется, что после того, как окно приемника TCP заполнится на XBox, он только явно повторно объявляет об обновлении окна в ответ на Zero Window Probes, которые содержат 1 байт данных полезной нагрузки.

В то время как машины под управлением Windows отправляют зонды с нулевым окном, содержащие 1-байтовую полезную нагрузку, машины под управлением Linux отправляют зонды, содержащие 0-байтовые полезные данные (чистые ACK).

В идеальных условиях сети это не проблема, поскольку получатель будет всегда посылать сообщение ACK об обновлении одного окна после того, как он освободит достаточно места в своем окне, чтобы избежать синдрома глупого окна. Однако, если этот пакет обновления одного окна будет пропущен, он никогда больше не ответит на устройство Android на базе Linux, потому что стек TCP на этих устройствах использует Zero Window Probes с 0-байтовой полезной нагрузкой (они выглядят как пакеты Keep Alive для Wirehsark ).

Задержка TCP между XBox и WMP выглядит так: Машины на базе Linux отправляют зонды, содержащие 0-байтовые полезные данные (чистые ACK).

В идеальных сетевых условиях это не проблема, поскольку получатель всегда отправляет одно сообщение ACK обновления окна как только он освободит достаточно места в окне, чтобы избежать синдрома глупого окна. Однако, если этот пакет обновления одного окна будет пропущен, он никогда больше не ответит на устройство Android на базе Linux, потому что стек TCP на этих устройствах использует Zero Window Probes с 0-байтовой полезной нагрузкой (они выглядят как пакеты Keep Alive для Wirehsark ).

Задержка TCP между XBox и WMP выглядит так: Машины на базе Linux отправляют зонды, содержащие 0-байтовые полезные данные (чистые ACK).

В идеальных сетевых условиях это не проблема, поскольку получатель всегда отправляет сообщение ACK обновления одного окна как только он освободит достаточно места в окне, чтобы избежать синдрома глупого окна. Однако, если этот пакет обновления одного окна будет пропущен, он никогда больше не ответит на устройство Android на базе Linux, потому что стек TCP на этих устройствах использует Zero Window Probes с 0-байтовой полезной нагрузкой (они выглядят как пакеты Keep Alive для Wirehsark ).

Задержка TCP между XBox и WMP выглядит так: s освободил достаточно места в окне, чтобы избежать синдрома глупого окна. Однако, если этот пакет обновления одного окна будет пропущен, он никогда больше не ответит на устройство Android на базе Linux, потому что стек TCP на этих устройствах использует Zero Window Probes с 0-байтовой полезной нагрузкой (они выглядят как пакеты Keep Alive для Wirehsark ).

Задержка TCP между XBox и WMP выглядит так: s освободил достаточно места в окне, чтобы избежать синдрома глупого окна. Однако, если этот пакет обновления одного окна будет пропущен, он никогда больше не ответит на устройство Android на базе Linux, потому что стек TCP на этих устройствах использует Zero Window Probes с 0-байтовой полезной нагрузкой (они выглядят как пакеты Keep Alive для Wirehsark ).

Задержка TCP между XBox и WMP выглядит так:


   4966 92.330358   10.0.2.214            10.0.2.133            TCP      [TCP ZeroWindow] 27883 > 10243 [ACK] Seq=183 Ack=1723007 Win=0 Len=0
   4971 92.648068   10.0.2.133            10.0.2.214            TCP      [TCP ZeroWindowProbe] 10243 > 27883 [ACK] Seq=1723007 Ack=183 Win=64240 Len=1
   4972 92.649009   10.0.2.214            10.0.2.133            TCP      [TCP ZeroWindowProbeAck] [TCP ZeroWindow] 27883 > 10243 [ACK] Seq=183 Ack=1723007 Win=0 Len=0
   4977 93.256579   10.0.2.133            10.0.2.214            TCP      [TCP ZeroWindowProbe] 10243 > 27883 [ACK] Seq=1723007 Ack=183 Win=64240 Len=1
   4978 93.263118   10.0.2.214            10.0.2.133            TCP      [TCP ZeroWindowProbeAck] [TCP ZeroWindow] 27883 > 10243 [ACK] Seq=183 Ack=1723007 Win=0 Len=0
   4999 94.310534   10.0.2.214            10.0.2.133            TCP      [TCP Window Update] 27883 > 10243 [ACK] Seq=183 Ack=1723007 Win=16384 Len=0

Обратите внимание, что Xbox активно отвечает на пакеты Zero Window Probe.

Обычная задержка TCP между XBox и клиентом Android выглядит следующим образом:


7099 174.844077  10.0.2.214            10.0.2.183            TCP [TCP ZeroWindow] [TCP ACKed lost segment] 20067 > ssdp [ACK] Seq=143 Ack=2962598 Win=0 Len=0
 7100 175.067981  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=2962597 Ack=143 Win=6912 Len=0
 7107 175.518024  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=2962597 Ack=143 Win=6912 Len=0
 7108 175.894079  10.0.2.214            10.0.2.183            TCP [TCP Window Update] 20067 > ssdp [ACK] Seq=143 Ack=2962598 Win=16384 Len=0

Обратите внимание, что XBox не отвечает на пакеты KeepAlive.

Если первоначальное объявление об обновлении окна пропущено, задержка TCP между XBox и моим устройством Android выглядит следующим образом:


 7146 175.925019  10.0.2.214            10.0.2.183            TCP [TCP ZeroWindow] 20067 > ssdp [ACK] Seq=143 Ack=3000558 Win=0 Len=0
 7147 176.147901  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7155 176.597820  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7165 177.498087  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7218 179.297763  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7297 182.897804  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7449 190.097780  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 7759 204.498070  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 8412 233.298081  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
 9617 290.898134  10.0.2.183            10.0.2.214            TCP [TCP Keep-Alive|TCP Keep-Alive] ssdp > 20067 [ACK] Seq=3000557 Ack=143 Win=6912 Len=0
11326 358.047838  10.0.2.214            10.0.2.183            TCP      20067 > ssdp [FIN, ACK] Seq=143 Ack=3000558 Win=16384 Len=0

Обратите внимание, что XBox никогда не объявляет о своем открытом окне повторно и в конечном итоге завершает соединение.

Я подтвердил свою теорию, написав небольшую программу внедрения пакетов. Когда я попадаю в стойло, я могу запустить вручную созданный пакет TCP Zero Window Probe. Когда это произойдет, XBox мгновенно оживает и продолжает работать в обычном режиме. К сожалению, я не могу сделать это из своего приложения, потому что для создания такого пакета требуется возможность CAP_NET_RAW, а я не могу предоставить ее своему приложению.

Вот вышеупомянутый случай с введенным вручную нулевым окном Зонд (упаковка 7258). Правильные номера seq / ack даже не требуются. Единственное, что требуется, - это один байт данных.


   7253 373.274394  10.0.2.214            10.0.2.186            TCP      [TCP ZeroWindow] 39378 > ssdp [ACK] Seq=3775184695 Ack=1775679761 Win=0 Len=0
   7254 375.367317  10.0.2.186            10.0.2.214            TCP      [TCP Keep-Alive] ssdp > 39378 [ACK] Seq=1775679760 Ack=3775184695 Win=3456 Len=0
   7255 379.562480  10.0.2.186            10.0.2.214            TCP      [TCP Keep-Alive] ssdp > 39378 [ACK] Seq=1775679760 Ack=3775184695 Win=3456 Len=0
   7256 387.953095  10.0.2.186            10.0.2.214            TCP      [TCP Keep-Alive] ssdp > 39378 [ACK] Seq=1775679760 Ack=3775184695 Win=3456 Len=0
   7257 404.703312  10.0.2.186            10.0.2.214            TCP      [TCP Keep-Alive] ssdp > 39378 [ACK] Seq=1775679760 Ack=3775184695 Win=3456 Len=0
   7258 406.571301  10.0.2.186            10.0.2.214            TCP      [TCP ACKed lost segment] [TCP Retransmission] ssdp > 39378 [ACK] Seq=1 Ack=1 Win=1 Len=1
   7259 406.603512  10.0.2.214            10.0.2.186            TCP      39378 > ssdp [ACK] Seq=3775184695 Ack=1775679761 Win=16384 Len=0

Поскольку числа TCP Seq / Ack неверны, Wireshark интерпретирует пакет как случайную передачу данных с недопустимым ACK, но XBox, тем не менее, возвращается к жизни и снова начинает потоковую передачу.

  • Есть ли способ получить возможности CAP_NET_RAW в приложении Android, не требуя рутирования устройства?
  • Есть ли какой-нибудь другой трюк, который я могу использовать, чтобы заставить TCP-уровень Linux отправлять свои зонды нулевого окна с 1 байтом данные полезной нагрузки?
  • Есть ли какой-нибудь другой неясный вариант TCP, который я мог бы попробовать, который позволил бы мне разбудить стек TCP XBox?
  • Есть ли какой-нибудь другой внеполосный подход, чтобы убедить XBox отправить еще одно обновление окна?
  • Есть ли какой-нибудь другой совершенно не связанный подход, который я мог бы рассмотреть?

Редактировать: Это описание почему предоставленные предложения не работают.

  1. TCP_NODELAY влияет только на то, как пакеты отправляются, когда окно открыто. В частности, установка этого параметра предотвращает ожидание стеком TCP в течение нескольких мс дополнительных данных в попытке создать пакет TCP, заполняющий MSS. Это не позволяет отправлять данные, когда окно получателя закрыто.

  2. TCP_QUICKACK влияет на способ приема пакетов ACK хоста. Проблема, с которой я столкнулся, заключается в том, что мне нужно изменить способ подтверждения отправителем пакетов , которые он получает.

  3. MSG_OOB устанавливает только флаг срочности TCP. Срочные данные не обрабатываются по-разному в том, что касается окон, и по-прежнему не будут отправлены, когда окно получателя закрыто.

  4. Изменение алгоритма управления перегрузкой TCP тоже не поможет. Поскольку XBox принудительно ограничивает скорость отправки данных скоростью воспроизведения MP3, практически невозможно избежать заполнения окна перегрузки. Можно было бы уменьшить окно перегрузки, сделав вывод о пропускной способности, но это только уменьшило бы вероятность заполнения окна перегрузки, но не предотвратило бы это полностью.

  5. Использование UDP не является вариантом, поскольку использование стека UPnP является обязательным требованием , а UPnP доставляет данные через HTTP и, следовательно, TCP.

15
задан Jason LeBrun 31 January 2011 в 18:24
поделиться