Действующие лица

web.sta – web-прило­жение, целевой браузер Internet Explorer версии 9 и 11
TextSystem – standalone прило­жение, написанное на Java/Swing
IntermediateLayer – Client-Server прило­жение, которое представляет собой связующее звено между web.sta и TextSystem. 

web.sta может вызвать TextSystem через IntermediateLayer. Для этого IntermediateLayer создаёт http server и web-прило­жение web.sta отправляет GET или POST запросы на localhost. Там IntermediateLayer обраба­тывает параметры запроса и стартует TextSystem. Обратной связи не требуется, поэтому схема взаимо­дей­ствия проста и доста­точно надёжна.

Citrix

В окружении Citrix мы не можем создать несколько слушающих сокетов на одном IP адресе и порте. Тут или надо менять порт, или же менять IP адрес. Но Citrix предо­ставляет специ­альный механизм для обхода этого ограни­чения, без изменения алгоритма работы программы. Этот механизм называется “Virtual IP Loopback”. Админи­стратору доста­точно указать необхо­димые прило­жения в панели конфи­гу­ри­ро­вания Citrix и прило­жение, которое использует localhost для сокетных соеди­нений, будет получать не 127.0.0.1, а IP адрес вида 127.0.0.<SID+1>, где SID это иденти­фи­катор сессии пользо­вателя Windows.

Проблема

Всё это прекрасно работало под IE9 (да и с другими браузерами тоже) на WindowsServer2008 R2. А потом клиентам захотелось чего-то нового и появился WindowsServer2012 R2 c IE11. И вся система перестала работать. Независимо от настроек Citrix IE11 всегда, при указании localhost, пытается установить соеди­нение на 127.0.0.1, а там никто не слушает. После небольшого иссле­до­вания мы пришли к выводу, что это баг именно в IE11.

RoutingService

Если вирту­а­ли­зация для localhost не работает из коробки Citrix для IE11, то давайте напишем её сами! Для этих целей мы решили написать windows service, который будет простейшим web сервером, слушать на 127.0.0.1 и перена­правлять запросы на нужные инстансы IntermediateLayer, основы­ваясь на номере сессии пользо­вателя. Простого решения получить SID мы не нашли, но в переменных окружения мы сразу обнаружили SESSIONNAME. В IE через ActiveX мы получаем переменную окружения, передаем её в качестве параметра в http запрос, в RoutingService по имени сессии мы через wtsapi32.lib получаем номер сессии. А затем перена­правляем http запрос и соответ­ственно возвращаем ответ.

Что-то пошло не так

Начали тести­ровать и внедрять наш сервис. Но не всё оказалось так радужно, как хотелось бы. Как оказалось имя сессии может меняться, правда мы так и не поняли в каких условиях это проис­ходит, а разби­раться ещё и с этим, как всегда не хватало времени. Но часто случалось, что имя сессии изменилось, а IE11 знает только перво­на­чальное значение переменной окружения. И упорно передаёт это значение на RoutingService.

А что там в реестре?

Надо найти другой способ получать sessionname. Поискали инфор­мацию о сессиях в реестре и вот что нашли: в HKEY_CURRENT_USER\Volatile Environment можно получить список сессий текущего пользователя.

Если сессия пользо­вателя одна – то вообще всё прекрасно, прочитали и используем. А если сессий одного пользо­вателя много, то надо как-то определить, в какой же мы сессии находимся. Ничего лучше, чем сопоставить путь к папке временных файлов, мы не придумали.

Вот пример:

В IE получаем текущий путь к TEMP, используя ActiveX Scripting.FileSystemObject. Таким образом нам удалось получить имя нашей сессии. Но это не всё. Значения ключей под Volatile Environment – это, собственно, SID и есть. То есть мы можем сразу в JavaScript получить необхо­димый IP адрес и оправить запрос на него.

Будем упрощать? 

В итоге мы можем получить SID и устанав­ливать соеди­нение напрямую, без исполь­зо­вания RoutingService. Но решение всё равно не выглядит красивым. Изучение интернета показало, что проблема есть, но решение этой проблемы нигде не описы­вается. А сам Microsoft молчит.

Так что, возможно, кому-то наш опыт будет полезен в решении этой специ­фичной проблемы.