diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/strings.resx b/src/System.ServiceModel.NetNamedPipe/src/Resources/strings.resx
index 9b4bdd49b11..24ab49a1ce5 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/strings.resx
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/strings.resx
@@ -213,4 +213,10 @@
NetNamedPipe is not supported on this platform.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+
+ The package full name '{0}' is invalid.
+
\ No newline at end of file
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.cs.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.cs.xlf
index 629f47210b3..a4ef5fd2964 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.cs.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.cs.xlf
@@ -12,6 +12,11 @@
Na {0} neposlouchal žádný koncový bod, který by mohl přijmout zprávu. To je často způsobeno nesprávnou adresou nebo akcí SOAP. Další informace zjistíte podle hodnoty vlastnosti InnerException (je-li přítomna).
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Do kanálu nelze zapisovat ani z něj číst, protože již probíhá proces jeho uzavírání.
@@ -142,6 +147,11 @@
Časový limit větší než hodnota Int32.MaxValue TotalMilliseconds (přibližně 24 dní) nelze akceptovat. Pokud chcete časový limit zakázat, zadejte hodnotu TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Pokus o připojení ke koncovému bodu pojmenovaného kanálu na {1} se nezdařil. Bude proveden další pokus s celkovým časovým limitem {0}.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.de.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.de.xlf
index 8135873b2cd..6145636390c 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.de.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.de.xlf
@@ -12,6 +12,11 @@
Es war kein an {0} lauschender Endpunkt vorhanden, der die Nachricht akzeptieren konnte. Dies wird häufig durch eine fehlerhafte Adresse oder SOAP-Aktion verursacht. Weitere Details finden Sie unter "InnerException" (sofern vorhanden).
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Schreiben in oder Lesen aus der Pipe ist nicht möglich, da die Pipe bereits geschlossen wird.
@@ -142,6 +147,11 @@
Zeitlimits, die größer als Int32.MaxValue TotalMilliseconds (ca. 24 Tage) sind, können nicht akzeptiert werden. Geben Sie den TimeSpan.MaxValue an, um das Zeitlimit zu deaktivieren.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Fehler beim Versuch, eine Verbindung mit dem Named Pipe-Endpunkt "{1}" herzustellen. Es wird ein weiterer Versuch unternommen. Im Gesamtzeitlimit verbleiben {0}.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.es.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.es.xlf
index 4436b7aea9b..f76e30a2637 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.es.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.es.xlf
@@ -12,6 +12,11 @@
No había ningún punto de conexión escuchando en {0} que pudiera aceptar el mensaje. La causa suele ser una dirección o una acción SOAP incorrecta. Consulte InnerException, si está presente, para obtener más información.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.No se puede escribir ni leer en la canalización porque ya está en proceso de cerrarse.
@@ -142,6 +147,11 @@
No se pueden aceptar valores de tiempo de espera mayores que Int32.MaxValue TotalMilliseconds (aproximadamente 24 días). Para deshabilitar el tiempo de espera, especifique TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Error al intentar conectar al extremo de canalización con nombre en '{1}'. Se realizará otro intento con {0} de tiempo de espera global restante.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.fr.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.fr.xlf
index 06b8902b894..a35eb7ca299 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.fr.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.fr.xlf
@@ -12,6 +12,11 @@
Il n'existait pas de point de terminaison à l'écoute sur {0} pouvant accepter le message. Ceci est souvent dû à une adresse ou une action SOAP incorrecte. S'il est présent, consultez InnerException pour plus d'informations.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Le canal n'est pas accessible en lecture et en écriture car il est déjà en cours de fermeture.
@@ -142,6 +147,11 @@
Les délais d'expiration supérieurs à Int32.MaxValue TotalMilliseconds (soit environ 24 jours) ne peuvent pas être appliqués. Pour désactiver le délai d'expiration, spécifiez TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Une tentative de connexion au point de terminaison du canal nommé à '{1}' a échoué. Une autre tentative sera effectuée avec {0} restants dans le délai d'attente globale.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.it.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.it.xlf
index b8ccab439c0..f5a21ae1ef5 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.it.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.it.xlf
@@ -12,6 +12,11 @@
Non è disponibile alcun endpoint in ascolto su {0} in grado di accettare il messaggio. Questo problema dipende spesso da un'azione SOAP o da un indirizzo non corretto. Per maggiori dettagli, vedere InnerException, se presente.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Impossibile scrivere sulla pipe o leggere da essa perché è già in fase di chiusura.
@@ -142,6 +147,11 @@
Non è possibile rispettare i timeout in cui il valore di TotalMilliseconds è maggiore di Int32.MaxValue (circa 24 giorni). Per disabilitare il timeout, specificare TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Tentativo di connessione all'endpoint della named pipe su '{1}' non riuscito. Verrà effettuato un altro tentativo con {0} rimanenti nel timeout complessivo.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ja.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ja.xlf
index 7a4990ed7b2..c1d63dffc30 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ja.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ja.xlf
@@ -12,6 +12,11 @@
メッセージを受信できる {0} でリッスンしているエンドポイントがありませんでした。これは一般に、アドレスまたは SOAP アクションが正しくない場合に発生します。詳細については、InnerException を参照してください (もしあれば)。
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.このパイプは既にクローズ処理に入っているため、書き込みも読み取りもできません。
@@ -142,6 +147,11 @@
Int32.MaxValue TotalMilliseconds (約 24 日) よりも大きな値のタイムアウトは受け付けられません。タイムアウトを無効にするには、TimeSpan.MaxValue を指定してください。
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.'{1}' の名前付きパイプ エンドポイントに接続しようとして失敗しました。合計タイムアウト時間の残りの {0} で再試行します。
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ko.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ko.xlf
index 7d0caa88e6b..871652309d8 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ko.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ko.xlf
@@ -12,6 +12,11 @@
메시지를 수락할 수 있는 {0}에서 수신 대기 중인 엔드포인트가 없습니다. 이것은 흔히 잘못된 주소나 SOAP 동작으로 인해 발생합니다. 자세한 내용은 InnerException(있을 경우)을 참조하세요.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.파이프를 이미 닫는 중이기 때문에 파이프에 쓰거나 파이프에서 읽을 수 없습니다.
@@ -142,6 +147,11 @@
Int32.MaxValue TotalMilliseconds(약 24일)보다 큰 시간 제한은 허용되지 않습니다. 시간 제한을 사용하지 않으려면 TimeSpan.MaxValue를 지정하세요.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.'{1}'의 명명된 파이프 끝점에 연결할 수 없습니다. 전체 시간 제한에서 남아 있는 {0} 동안 다시 시도됩니다.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pl.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pl.xlf
index b84d6f3e626..58baa9637b0 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pl.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pl.xlf
@@ -12,6 +12,11 @@
W elemencie {0} brak nasłuchującego punktu końcowego, który mógłby odebrać komunikat. Jest to często spowodowane niepoprawnym adresem lub akcją SOAP. Sprawdź właściwość InnerException (jeśli jest obecna), aby uzyskać więcej szczegółowych informacji.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Nie można odczytać z potoku ani zapisać do niego, ponieważ trwa zamykanie potoku.
@@ -142,6 +147,11 @@
Limity czasu większe niż Int32.MaxValue TotalMilliseconds (około 24 dni) nie mogą być uwzględniane. Aby wyłączyć limit czasu, określ wartość TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Próba połączenia się z punktem końcowym nazwanego potoku na „{1}” nie powiodła się. Zostanie podjęta kolejna próba z {0} pozostałych w ogólnym limicie czasu.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pt-BR.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pt-BR.xlf
index 5d3832134e7..00005ff9c43 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pt-BR.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.pt-BR.xlf
@@ -12,6 +12,11 @@
Não havia nenhum ponto de extremidade em escuta em {0} capaz de aceitar a mensagem. Em geral, isso é causado por endereço ou ação de SOAP incorretos. Consulte InnerException, se presente, para obter mais detalhes.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Não é possível gravar no pipe ou ler a partir do pipe porque ele já está no processo de fechamento.
@@ -142,6 +147,11 @@
Os tempos limites maiores que Int32.MaxValue TotalMilliseconds (aproximadamente 24 dias) não podem ser honrados. Para desabilitar o tempo limite, especifique TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Falha de uma tentativa de conectar ao ponto de extremidade de pipe nomeado em '{1}'. Outra tentativa será feita com {0} restante no tempo limite geral.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ru.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ru.xlf
index fa106487092..2d409663035 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ru.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.ru.xlf
@@ -12,6 +12,11 @@
Прослушивание по {0} не выполняла ни одна конечная точка, которая могла бы принять сообщение. Среди прочих причин это могло быть вызвано неправильным адресом или действием SOAP. Подробнее см. в описании InnerException (если имеется).
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Невозможно выполнить запись или чтение из канала, так как он уже находится в процессе закрытия.
@@ -142,6 +147,11 @@
Время ожидания, превышающее Int32.MaxValue TotalMilliseconds (приблизительно 24 дня), не учитывается. Чтобы отключить время ожидания, укажите TimeSpan.MaxValue.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.Ошибка при попытке подключения к конечной точке "{1}" именованного канала. Следующая попытка будет выполнена при остатке {0} от общего тайм-аута.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.tr.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.tr.xlf
index 6d75a2444fe..72cddfa6ad7 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.tr.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.tr.xlf
@@ -12,6 +12,11 @@
{0} konumunda dinleme yapan, iletiyi kabul edebilecek uç nokta yoktu. Bunun nedeni genellikle hatalı bir adres ya da SOAP eylemidir. Ayrıntılar için varsa InnerException öğesine bakın.
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.Kanala zaten kapatma işlemi uygulandığından kanala yazılamıyor ya da buradan okuma yapılamıyor.
@@ -142,6 +147,11 @@
Int32.MaxValue TotalMilliseconds (yaklaşık 24 gün) değerinden büyük zaman aşımı değerleri dikkate alınmaz. Zaman aşımını devre dışı bırakmak için TimeSpan.MaxValue değeri belirtin.
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.'{1}' konumunda adlandırılan kanal bitiş noktasına bağlanma denemesi başarısız oldu. Genel zaman aşımında {0} kaldığında başka bir deneme yapılacak.
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hans.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hans.xlf
index 00fb99328e0..4cbe7e7f804 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hans.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hans.xlf
@@ -12,6 +12,11 @@
没有终结点在侦听可以接受消息的 {0}。这通常是由于不正确的地址或者 SOAP 操作导致的。如果存在此情况,请参见 InnerException 以了解详细信息。
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.无法写入或读取管道,因为它已在正在被关闭的进程中。
@@ -142,6 +147,11 @@
无法处理大于 Int32.MaxValue TotalMilliseconds (大约 24 天)的超时。要禁用超时,请指定 TimeSpan.MaxValue。
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.尝试连接到位于“{1}”的已命名管道终结点失败。总计超时剩余{0}时,将再次进行尝试。
diff --git a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hant.xlf b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hant.xlf
index 6a167504e72..a81e3b55e94 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hant.xlf
+++ b/src/System.ServiceModel.NetNamedPipe/src/Resources/xlf/strings.zh-Hant.xlf
@@ -12,6 +12,11 @@
沒有任何在 {0} 上進行接聽的端點可以接受該訊息。這通常是由不正確位址或 SOAP 動作所造成。若有 InnerException,可參閱以取得詳細資訊。
+
+ The package full name '{0}' is invalid.
+ The package full name '{0}' is invalid.
+
+ The pipe cannot be written to or read from because it is already in the process of being closed.管道正在關閉中,因此無法寫入或讀取。
@@ -142,6 +147,11 @@
無法遵循大於 Int32.MaxValue TotalMilliseconds (大約等於 24 天) 的逾時。若要停用逾時,請指定 TimeSpan.MaxValue。
+
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+ The Session value '{0}' is invalid. Please specify 'CurrentSession','ServiceSession' or a valid non-negative Windows Session Id.
+
+ An attempt to connect to the named pipe endpoint at '{1}' failed. Another attempt will be made with {0} remaining in the overall timeout.嘗試在 '{1}' 連接到具名管道端點已失敗。在整體逾時之前還可以嘗試 {0} 次。
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/AppContainerInfo.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/AppContainerInfo.cs
new file mode 100644
index 00000000000..41f3a9f06bc
--- /dev/null
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/AppContainerInfo.cs
@@ -0,0 +1,215 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.ComponentModel;
+using System.Runtime;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Security.Principal;
+using System.Text;
+using static System.ServiceModel.Channels.UnsafeNativeMethods;
+
+namespace System.ServiceModel.Channels
+{
+ ///
+ /// This class provides the entry points into Application Container related functionality.
+ /// Callers are expected to check if the application is running in an AppContainer before
+ /// invoking any of the methods in this class.
+ ///
+ [SupportedOSPlatform("windows")]
+ internal class AppContainerInfo
+ {
+ static object s_thisLock = new object();
+ static bool s_isAppContainerSupported;
+ static bool s_isRunningInAppContainer;
+ static volatile bool s_isRunningInAppContainerSet;
+ static object s_isRunningInAppContainerLock = new object();
+ static int? s_currentSessionId;
+
+ static AppContainerInfo()
+ {
+ // AppContainers are supported starting in Win8
+ s_isAppContainerSupported = OSEnvironmentHelper.IsAtLeast(OSVersion.Win8);
+
+ if (!s_isAppContainerSupported)
+ {
+ s_isRunningInAppContainerSet = true;
+ }
+ }
+
+ AppContainerInfo(int sessionId, string namedObjectPath)
+ {
+ this.SessionId = sessionId;
+ this.NamedObjectPath = namedObjectPath;
+ }
+
+ internal static bool IsAppContainerSupported
+ {
+ get
+ {
+ return s_isAppContainerSupported;
+ }
+ }
+
+ internal static bool IsRunningInAppContainer
+ {
+ get
+ {
+ // The AppContainerInfo.RunningInAppContainer() API may throw security exceptions,
+ // so cannot be used inside the static constructor of the class.
+ if (!s_isRunningInAppContainerSet)
+ {
+ lock (s_isRunningInAppContainerLock)
+ {
+ if (!s_isRunningInAppContainerSet)
+ {
+ s_isRunningInAppContainer = AppContainerInfo.RunningInAppContainer();
+ s_isRunningInAppContainerSet = true;
+ }
+ }
+ }
+
+ return s_isRunningInAppContainer;
+ }
+ }
+
+ internal int SessionId { get; private set; }
+
+ internal string NamedObjectPath { get; private set; }
+
+ internal static AppContainerInfo CreateAppContainerInfo(string fullName, int sessionId)
+ {
+ Fx.Assert(IsAppContainerSupported, "AppContainers are not supported.");
+ Fx.Assert(!string.IsNullOrEmpty(fullName), "fullName should be provided to initialize an AppContainerInfo.");
+
+ int appSession = sessionId;
+ if (appSession == ApplicationContainerSettings.CurrentSession)
+ {
+ lock (s_thisLock)
+ {
+ if (s_currentSessionId == null)
+ {
+ s_currentSessionId = AppContainerInfo.GetCurrentSessionId();
+ }
+ }
+
+ appSession = s_currentSessionId.Value;
+ }
+
+ string namedObjectPath = AppContainerInfo.GetAppContainerNamedObjectPath(fullName);
+ return new AppContainerInfo(appSession, namedObjectPath);
+ }
+
+ static bool RunningInAppContainer()
+ {
+ Fx.Assert(AppContainerInfo.IsAppContainerSupported, "AppContainers are not supported.");
+ SafeCloseHandle tokenHandle = null;
+ try
+ {
+ tokenHandle = AppContainerInfo.GetCurrentProcessToken();
+ return UnsafeNativeMethods.RunningInAppContainer(tokenHandle);
+ }
+ finally
+ {
+ if (tokenHandle != null)
+ {
+ tokenHandle.Dispose();
+ }
+ }
+ }
+
+ static string GetAppContainerNamedObjectPath(string name)
+ {
+ // 1. Derive the PackageFamilyName(PFN) from the PackageFullName
+ // 2. Get the AppContainerSID from the PFN
+ // 3. Get the NamedObjectPath from the AppContainerSID
+ Fx.Assert(AppContainerInfo.IsAppContainerSupported, "AppContainers are not supported.");
+ IntPtr appContainerSid = IntPtr.Zero;
+
+ // Package Full Name => Package family name
+ uint packageFamilyNameLength = UnsafeNativeMethods.MAX_PATH;
+ StringBuilder packageFamilyNameBuilder = new StringBuilder((int)UnsafeNativeMethods.MAX_PATH);
+ string packageFamilyName;
+ int errorCode = UnsafeNativeMethods.PackageFamilyNameFromFullName(name, ref packageFamilyNameLength, packageFamilyNameBuilder);
+ if (errorCode != UnsafeNativeMethods.ERROR_SUCCESS)
+ {
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode, SR.Format(SR.PackageFullNameInvalid, name)));
+ }
+
+ packageFamilyName = packageFamilyNameBuilder.ToString();
+
+ try
+ {
+ // PackageFamilyName => AppContainerSID
+ int hresult = UnsafeNativeMethods.DeriveAppContainerSidFromAppContainerName(
+ packageFamilyName,
+ out appContainerSid);
+ if (hresult != 0)
+ {
+ errorCode = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode));
+ }
+
+ // AppContainerSID => NamedObjectPath
+ StringBuilder namedObjectPath = new StringBuilder((int)UnsafeNativeMethods.MAX_PATH);
+ uint returnLength = 0;
+ if (!UnsafeNativeMethods.GetAppContainerNamedObjectPath(
+ IntPtr.Zero,
+ appContainerSid,
+ UnsafeNativeMethods.MAX_PATH,
+ namedObjectPath,
+ ref returnLength))
+ {
+ errorCode = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode));
+ }
+
+ return namedObjectPath.ToString();
+ }
+ finally
+ {
+ if (appContainerSid != IntPtr.Zero)
+ {
+ UnsafeNativeMethods.FreeSid(appContainerSid);
+ }
+ }
+ }
+
+ static int GetCurrentSessionId()
+ {
+ Fx.Assert(AppContainerInfo.IsAppContainerSupported, "AppContainers are not supported.");
+ SafeCloseHandle tokenHandle = null;
+ try
+ {
+ tokenHandle = AppContainerInfo.GetCurrentProcessToken();
+ return UnsafeNativeMethods.GetSessionId(tokenHandle);
+ }
+ finally
+ {
+ if (tokenHandle != null)
+ {
+ tokenHandle.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// Returns the process token using TokenAccessLevels.Query
+ ///
+ /// ProcessToken as a SafeCloseHandle.
+ static SafeCloseHandle GetCurrentProcessToken()
+ {
+ SafeCloseHandle tokenHandle = null;
+ if (!UnsafeNativeMethods.OpenProcessToken(
+ UnsafeNativeMethods.GetCurrentProcess(),
+ TokenAccessLevels.Query,
+ out tokenHandle))
+ {
+ int error = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(error));
+ }
+
+ return tokenHandle;
+ }
+ }
+}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/ApplicationContainerSettings.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/ApplicationContainerSettings.cs
new file mode 100644
index 00000000000..f2f0249c676
--- /dev/null
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/ApplicationContainerSettings.cs
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Globalization;
+using System.Runtime.Versioning;
+
+namespace System.ServiceModel.Channels
+{
+ [SupportedOSPlatform("windows")]
+ public sealed class ApplicationContainerSettings
+ {
+ public const int CurrentSession = ApplicationContainerSettingsDefaults.CurrentSession;
+ public const int ServiceSession = ApplicationContainerSettingsDefaults.ServiceSession;
+ const string GroupNameSuffixFormat = ";SessionId={0};PackageFullName={1}";
+
+ private int _sessionId;
+
+ internal ApplicationContainerSettings()
+ {
+ PackageFullName = ApplicationContainerSettingsDefaults.PackageFullNameDefaultString;
+ _sessionId = ApplicationContainerSettingsDefaults.CurrentSession;
+ }
+
+ ApplicationContainerSettings(ApplicationContainerSettings source)
+ {
+ PackageFullName = source.PackageFullName;
+ _sessionId = source._sessionId;
+ }
+
+ public string PackageFullName
+ {
+ get;
+ set;
+ }
+
+ public int SessionId
+ {
+ get
+ {
+ return _sessionId;
+ }
+
+ set
+ {
+ // CurrentSession default is -1 and expect the user to set
+ // non-negative windows session Id.
+ if (value < ApplicationContainerSettingsDefaults.CurrentSession)
+ {
+ throw FxTrace.Exception.Argument(nameof(value), SR.Format(SR.SessionValueInvalid, value));
+ }
+
+ _sessionId = value;
+ }
+ }
+
+ internal bool TargetingAppContainer
+ {
+ get
+ {
+ return !string.IsNullOrEmpty(this.PackageFullName);
+ }
+ }
+
+ internal ApplicationContainerSettings Clone()
+ {
+ return new ApplicationContainerSettings(this);
+ }
+
+ internal string GetConnectionGroupSuffix()
+ {
+ string suffix = string.Empty;
+ if (AppContainerInfo.IsAppContainerSupported && this.TargetingAppContainer)
+ {
+ suffix = string.Format(CultureInfo.InvariantCulture, GroupNameSuffixFormat, SessionId, PackageFullName);
+ }
+
+ return suffix;
+ }
+
+ internal bool IsMatch(ApplicationContainerSettings applicationContainerSettings)
+ {
+ if (applicationContainerSettings == null)
+ {
+ return false;
+ }
+
+ if (PackageFullName != applicationContainerSettings.PackageFullName)
+ {
+ return false;
+ }
+
+ if (_sessionId != applicationContainerSettings._sessionId)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/IConnectionOrientedConnectionSettings.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/IConnectionOrientedConnectionSettings.cs
index 4cf5d6ead03..c1b7b51aa02 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/IConnectionOrientedConnectionSettings.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/IConnectionOrientedConnectionSettings.cs
@@ -18,4 +18,9 @@ internal interface IConnectionOrientedTransportFactorySettings : ITransportFacto
// Audit
//ServiceSecurityAuditBehavior AuditBehavior { get; }
}
+
+ internal interface IPipeTransportFactorySettings
+ {
+ NamedPipeSettings PipeSettings { get; }
+ }
}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeChannelFactory.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeChannelFactory.cs
index 2252805622f..918eee9335f 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeChannelFactory.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeChannelFactory.cs
@@ -6,8 +6,7 @@
namespace System.ServiceModel.Channels
{
[SupportedOSPlatform("windows")]
-
- internal class NamedPipeChannelFactory : NetFramingTransportChannelFactory
+ internal class NamedPipeChannelFactory : NetFramingTransportChannelFactory, IPipeTransportFactorySettings
{
public NamedPipeChannelFactory(NamedPipeTransportBindingElement bindingElement, BindingContext context)
: base(bindingElement, context,
@@ -15,6 +14,10 @@ public NamedPipeChannelFactory(NamedPipeTransportBindingElement bindingElement,
bindingElement.ConnectionPoolSettings.IdleTimeout,
bindingElement.ConnectionPoolSettings.MaxOutboundConnectionsPerEndpoint)
{
+ if (bindingElement.PipeSettings != null)
+ {
+ this.PipeSettings = bindingElement.PipeSettings.Clone();
+ }
}
public override string Scheme
@@ -22,19 +25,24 @@ public override string Scheme
get { return Uri.UriSchemeNetPipe; }
}
+ public NamedPipeSettings PipeSettings
+ {
+ get; private set;
+ }
+
private static string GetConnectionGroupName(NamedPipeTransportBindingElement bindingElement)
{
- return bindingElement.ConnectionPoolSettings.GroupName;
+ return bindingElement.ConnectionPoolSettings.GroupName + bindingElement.PipeSettings.ApplicationContainerSettings.GetConnectionGroupSuffix();
}
public override IConnectionInitiator GetConnectionInitiator()
{
- return new PipeConnectionInitiator(ConnectionBufferSize);
+ return new PipeConnectionInitiator(ConnectionBufferSize, this);
}
protected override string GetConnectionPoolKey(EndpointAddress address, Uri via)
{
- return PipeConnectionInitiator.GetPipeName(via);
+ return PipeConnectionInitiator.GetPipeName(via, this);
}
protected override bool SupportsUpgrade(StreamUpgradeBindingElement upgradeBindingElement)
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeSettings.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeSettings.cs
new file mode 100644
index 00000000000..253352843f5
--- /dev/null
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeSettings.cs
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.Versioning;
+
+namespace System.ServiceModel.Channels
+{
+ [SupportedOSPlatform("windows")]
+ public sealed class NamedPipeSettings
+ {
+ internal NamedPipeSettings()
+ {
+ this.ApplicationContainerSettings = new ApplicationContainerSettings();
+ }
+
+ NamedPipeSettings(NamedPipeSettings elementToBeCloned)
+ {
+ if (elementToBeCloned.ApplicationContainerSettings != null)
+ {
+ this.ApplicationContainerSettings = elementToBeCloned.ApplicationContainerSettings.Clone();
+ }
+ }
+
+ public ApplicationContainerSettings ApplicationContainerSettings
+ {
+ get;
+ private set;
+ }
+
+ internal NamedPipeSettings Clone()
+ {
+ return new NamedPipeSettings(this);
+ }
+
+ internal bool IsMatch(NamedPipeSettings pipeSettings)
+ {
+ if (pipeSettings == null)
+ {
+ return false;
+ }
+
+ if (!this.ApplicationContainerSettings.IsMatch(pipeSettings.ApplicationContainerSettings))
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs
index 5cef9c13203..c2f6adea5f6 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/NamedPipeTransportBindingElement.cs
@@ -13,6 +13,7 @@ public class NamedPipeTransportBindingElement : ConnectionOrientedTransportBindi
{
private readonly List _allowedUsers = new List();
private readonly NamedPipeConnectionPoolSettings _connectionPoolSettings = new NamedPipeConnectionPoolSettings();
+ private NamedPipeSettings _namedPipeSettings = new NamedPipeSettings();
public NamedPipeTransportBindingElement() : base()
{
@@ -34,6 +35,7 @@ protected NamedPipeTransportBindingElement(NamedPipeTransportBindingElement elem
}
_connectionPoolSettings = elementToBeCloned._connectionPoolSettings.Clone();
+ _namedPipeSettings = elementToBeCloned._namedPipeSettings.Clone();
}
public NamedPipeConnectionPoolSettings ConnectionPoolSettings
@@ -41,6 +43,11 @@ public NamedPipeConnectionPoolSettings ConnectionPoolSettings
get { return _connectionPoolSettings; }
}
+ public NamedPipeSettings PipeSettings
+ {
+ get { return _namedPipeSettings; }
+ }
+
public override string Scheme
{
get { return Uri.UriSchemeNetPipe; }
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/PipeConnectionInitiator.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/PipeConnectionInitiator.cs
index e469819fe9b..1ee7c97ba88 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/PipeConnectionInitiator.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/PipeConnectionInitiator.cs
@@ -14,6 +14,7 @@
using System.Security.Principal;
using System.ServiceModel.Diagnostics;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
namespace System.ServiceModel.Channels
@@ -22,10 +23,12 @@ namespace System.ServiceModel.Channels
internal class PipeConnectionInitiator : IConnectionInitiator
{
private readonly int _bufferSize;
+ private readonly IPipeTransportFactorySettings _pipeSettings;
- public PipeConnectionInitiator(int bufferSize)
+ public PipeConnectionInitiator(int bufferSize, IPipeTransportFactorySettings pipeSettings)
{
_bufferSize = bufferSize;
+ _pipeSettings = pipeSettings;
}
private Exception CreateConnectFailedException(Uri remoteUri, PipeException innerException)
@@ -44,7 +47,7 @@ public async ValueTask ConnectAsync(Uri remoteUri, TimeSpan timeout
IConnection connection = null;
while (connection == null)
{
- connection = TryConnect(remoteUri, resolvedAddress, backoffHelper);
+ connection = TryConnect(remoteUri, resolvedAddress, backoffHelper);
if (connection == null)
{
await backoffHelper.WaitAndBackoffAsync();
@@ -67,8 +70,10 @@ public async ValueTask ConnectAsync(Uri remoteUri, TimeSpan timeout
internal const string UseBestMatchNamedPipeUriString = "wcf:useBestMatchNamedPipeUri";
internal static bool s_useBestMatchNamedPipeUri = AppContext.TryGetSwitch(UseBestMatchNamedPipeUriString, out bool enabled) && enabled;
- internal static string GetPipeName(Uri uri)
+ internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
{
+ AppContainerInfo appInfo = GetAppContainerInfo(transportFactorySettings);
+
// for wildcard hostName support, we first try and connect to the StrongWildcard,
// then the Exact HostName, and lastly the WeakWildcard
string[] hostChoices = new string[] { "+", uri.Host, "*" };
@@ -85,8 +90,7 @@ internal static string GetPipeName(Uri uri)
while (path.Length > 0)
{
-
- string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal]);
+ string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal], appInfo);
try
{
PipeSharedMemory sharedMemory = PipeSharedMemory.Open(sharedMemoryName, uri);
@@ -94,7 +98,7 @@ internal static string GetPipeName(Uri uri)
{
try
{
- string pipeName = sharedMemory.PipeName;
+ string pipeName = sharedMemory.GetPipeName(appInfo);
if (pipeName != null)
{
// Found a matching pipe name.
@@ -150,7 +154,7 @@ private void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolved
SR.TraceCodeInitiatingNamedPipeConnection,
new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
}
- resolvedAddress = GetPipeName(remoteUri);
+ resolvedAddress = GetPipeName(remoteUri, _pipeSettings);
const int backoffBufferMilliseconds = 150;
TimeSpan backoffTimeout;
if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
@@ -230,7 +234,7 @@ private IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTim
{
namedPipeClient.ReadMode = PipeTransmissionMode.Message;
}
- catch(Exception ex)
+ catch (Exception ex)
{
PipeException innerException = new PipeException(SR.Format(SR.PipeModeChangeFailed, ex.Message), ex.HResult);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
@@ -240,6 +244,22 @@ private IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTim
return new PipeConnection(namedPipeClient, _bufferSize);
}
+
+ static AppContainerInfo GetAppContainerInfo(IPipeTransportFactorySettings transportFactorySettings)
+ {
+ if (AppContainerInfo.IsAppContainerSupported &&
+ transportFactorySettings != null &&
+ transportFactorySettings.PipeSettings != null)
+ {
+ ApplicationContainerSettings appSettings = transportFactorySettings.PipeSettings.ApplicationContainerSettings;
+ if (appSettings != null && appSettings.TargetingAppContainer)
+ {
+ return AppContainerInfo.CreateAppContainerInfo(appSettings.PackageFullName, appSettings.SessionId);
+ }
+ }
+
+ return null;
+ }
}
[SupportedOSPlatform("windows")]
@@ -248,6 +268,7 @@ internal unsafe class PipeSharedMemory : IDisposable
internal const string PipeLocalPrefix = @"Local\";
private MemoryMappedFile _fileMapping;
private string _pipeName;
+ private string _pipeNameGuidPart;
private readonly Uri _pipeUri;
private PipeSharedMemory(MemoryMappedFile fileMapping, Uri pipeUri)
@@ -277,11 +298,11 @@ public static PipeSharedMemory Open(string sharedMemoryName, Uri pipeUri)
memoryMappedFile = MemoryMappedFile.OpenExisting("Global\\" + sharedMemoryName, MemoryMappedFileRights.Read,
HandleInheritability.None);
}
- catch(FileNotFoundException)
+ catch (FileNotFoundException)
{
return null;
}
- catch(IOException ioe)
+ catch (IOException ioe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(ioe, pipeUri));
}
@@ -299,6 +320,11 @@ public void Dispose()
}
}
+ static string BuildPipeName(string pipeGuid)
+ {
+ return AppContainerInfo.IsRunningInAppContainer ? string.Concat(PipeLocalPrefix, pipeGuid) : pipeGuid;
+ }
+
public string PipeName
{
get
@@ -308,7 +334,12 @@ public string PipeName
using (MemoryMappedViewStream view = GetView(false))
{
SharedMemoryContents contents = view.SafeMemoryMappedViewHandle.Read(0);
- _pipeName = contents.pipeGuid.ToString();
+ if (contents.isInitialized)
+ {
+ Thread.MemoryBarrier();
+ _pipeNameGuidPart = contents.pipeGuid.ToString();
+ _pipeName = BuildPipeName(_pipeNameGuidPart);
+ }
}
}
@@ -316,6 +347,27 @@ public string PipeName
}
}
+ internal string GetPipeName(AppContainerInfo appInfo)
+ {
+ if (appInfo == null)
+ {
+ return PipeName;
+ }
+ else if (PipeName != null)
+ {
+ // Build the PipeName for a pipe inside an AppContainer as follows
+ // \\.\Sessions\\\
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ @"\\.\Sessions\{0}\{1}\{2}",
+ appInfo.SessionId,
+ appInfo.NamedObjectPath,
+ _pipeNameGuidPart);
+ }
+
+ return null;
+ }
+
private static Exception CreatePipeNameCannotBeAccessedException(IOException ioe, Uri pipeUri)
{
Exception innerException = new PipeException(SR.Format(SR.PipeNameCanNotBeAccessed,
@@ -329,7 +381,7 @@ private MemoryMappedViewStream GetView(bool writable)
{
return _fileMapping.CreateViewStream(0, sizeof(SharedMemoryContents), writable ? MemoryMappedFileAccess.Write : MemoryMappedFileAccess.Read);
}
- catch(IOException ioe)
+ catch (IOException ioe)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(ioe, _pipeUri));
}
@@ -343,8 +395,28 @@ private struct SharedMemoryContents
}
}
+ [SupportedOSPlatform("windows")]
internal static class PipeUri
{
+ public static string BuildSharedMemoryName(string hostName, string path, bool global, AppContainerInfo appContainerInfo)
+ {
+ if (appContainerInfo == null)
+ {
+ return BuildSharedMemoryName(hostName, path, global);
+ }
+ else
+ {
+ //We need to use a session symlink for the lowbox appcontainer.
+ // Session\{0}\{1}\{2}\
+ return string.Format(
+ CultureInfo.InvariantCulture,
+ @"Session\{0}\{1}\{2}",
+ appContainerInfo.SessionId,
+ appContainerInfo.NamedObjectPath,
+ BuildSharedMemoryName(hostName, path, global));
+ }
+ }
+
public static string BuildSharedMemoryName(string hostName, string path, bool global)
{
StringBuilder builder = new StringBuilder();
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/TransportDefaults.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/TransportDefaults.cs
index f1357e3ea6e..2c5a8bc67f1 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/TransportDefaults.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/TransportDefaults.cs
@@ -20,4 +20,21 @@ internal static class ConnectionOrientedTransportDefaults
public const ProtectionLevel ProtectionLevel = Net.Security.ProtectionLevel.EncryptAndSign;
public const TransferMode TransferMode = ServiceModel.TransferMode.Buffered;
}
+
+ internal static class ApplicationContainerSettingsDefaults
+ {
+ internal const string CurrentUserSessionDefaultString = "CurrentSession";
+ internal const string Session0ServiceSessionString = "ServiceSession";
+ internal const string PackageFullNameDefaultString = null;
+
+ ///
+ /// The current session will be used for resource lookup.
+ ///
+ internal const int CurrentSession = -1;
+
+ ///
+ /// Session 0 is the NT Service session
+ ///
+ internal const int ServiceSession = 0;
+ }
}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/UnsafeNativeMethods.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/UnsafeNativeMethods.cs
index 4e96bf585ae..a141ac4f702 100644
--- a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/UnsafeNativeMethods.cs
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/Channels/UnsafeNativeMethods.cs
@@ -1,14 +1,247 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
+using System.Security.Principal;
+using System.Text;
+using Microsoft.Win32.SafeHandles;
+
namespace System.ServiceModel.Channels
{
+ [SupportedOSPlatform("windows")]
internal static class UnsafeNativeMethods
{
+ public const string KERNEL32 = "kernel32.dll";
+ public const string ADVAPI32 = "advapi32.dll";
+ public const string USERENV = "userenv.dll";
+
// WinError.h codes:
+ internal const int ERROR_SUCCESS = 0;
internal const int ERROR_FILE_NOT_FOUND = 0x2;
internal const int ERROR_BROKEN_PIPE = 109;
internal const int ERROR_PIPE_BUSY = 231;
internal const int ERROR_NO_DATA = 232;
+ // When querying for the token length
+ internal const int ERROR_INSUFFICIENT_BUFFER = 122;
+ public const uint MAX_PATH = 260;
+
+ [DllImport(USERENV, SetLastError = true)]
+ internal static extern int DeriveAppContainerSidFromAppContainerName
+ (
+ [In, MarshalAs(UnmanagedType.LPWStr)] string appContainerName,
+ out IntPtr appContainerSid
+ );
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ internal static extern IntPtr FreeSid
+ (
+ IntPtr pSid
+ );
+
+ // If the function succeeds, the return value is ERROR_SUCCESS and 'packageFamilyNameLength' contains the size of the data copied
+ // to 'packageFamilyName' (in WCHARs, including the null-terminator). If the function fails, the return value is a Win32 error code.
+ [DllImport(KERNEL32)]
+ internal static extern int PackageFamilyNameFromFullName
+ (
+ [In, MarshalAs(UnmanagedType.LPWStr)] string packageFullName,
+ ref uint packageFamilyNameLength,
+ [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder packageFamilyName
+ );
+
+ [DllImport(KERNEL32, SetLastError = true)]
+ internal static extern bool GetAppContainerNamedObjectPath
+ (
+ IntPtr token,
+ IntPtr appContainerSid,
+ uint objectPathLength,
+ [In, Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder objectPath,
+ ref uint returnLength
+ );
+
+ [DllImport(KERNEL32, SetLastError = true)]
+ internal static extern IntPtr GetCurrentProcess();
+
+ [DllImport(ADVAPI32, SetLastError = true)]
+ [ResourceExposure(ResourceScope.None)]
+ internal static extern bool OpenProcessToken
+ (
+ IntPtr ProcessHandle,
+ TokenAccessLevels DesiredAccess,
+ out SafeCloseHandle TokenHandle
+ );
+
+ // Token marshalled as byte[]
+ [DllImport(ADVAPI32, SetLastError = true)]
+ static extern unsafe bool GetTokenInformation
+ (
+ SafeCloseHandle tokenHandle,
+ TOKEN_INFORMATION_CLASS tokenInformationClass,
+ byte[] tokenInformation,
+ uint tokenInformationLength,
+ out uint returnLength
+ );
+
+ // Token marshalled as uint
+ [DllImport(ADVAPI32, SetLastError = true)]
+ static extern bool GetTokenInformation
+ (
+ SafeCloseHandle tokenHandle,
+ TOKEN_INFORMATION_CLASS tokenInformationClass,
+ out uint tokenInformation,
+ uint tokenInformationLength,
+ out uint returnLength
+ );
+
+ internal static unsafe SecurityIdentifier GetAppContainerSid(SafeCloseHandle tokenHandle)
+ {
+ // Get length of buffer needed for sid.
+ uint returnLength = GetTokenInformationLength(
+ tokenHandle,
+ TOKEN_INFORMATION_CLASS.TokenAppContainerSid);
+
+ byte[] tokenInformation = new byte[returnLength];
+ fixed (byte* pTokenInformation = tokenInformation)
+ {
+ if (!GetTokenInformation(
+ tokenHandle,
+ TOKEN_INFORMATION_CLASS.TokenAppContainerSid,
+ tokenInformation,
+ returnLength,
+ out returnLength))
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode));
+ }
+
+ TokenAppContainerInfo* ptg = (TokenAppContainerInfo*)pTokenInformation;
+ return new SecurityIdentifier(ptg->psid);
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct TokenAppContainerInfo
+ {
+ public IntPtr psid;
+ }
+
+ internal static int GetSessionId(SafeCloseHandle tokenHandle)
+ {
+ uint sessionId;
+ uint returnLength;
+
+ if (!GetTokenInformation(
+ tokenHandle,
+ TOKEN_INFORMATION_CLASS.TokenSessionId,
+ out sessionId,
+ sizeof(uint),
+ out returnLength))
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode));
+ }
+
+ return (int)sessionId;
+ }
+
+ private static uint GetTokenInformationLength(SafeCloseHandle token, TOKEN_INFORMATION_CLASS tokenInformationClass)
+ {
+ uint lengthNeeded;
+ bool success;
+ if (!(success = GetTokenInformation(
+ token,
+ tokenInformationClass,
+ null,
+ 0,
+ out lengthNeeded)))
+ {
+ int error = Marshal.GetLastWin32Error();
+ if (error != ERROR_INSUFFICIENT_BUFFER)
+ {
+ throw new Win32Exception(error);
+ }
+ }
+
+ return lengthNeeded;
+ }
+
+ internal static bool RunningInAppContainer(SafeCloseHandle tokenHandle)
+ {
+ uint runningInAppContainer;
+ uint returnLength;
+ if (!GetTokenInformation(
+ tokenHandle,
+ TOKEN_INFORMATION_CLASS.TokenIsAppContainer,
+ out runningInAppContainer,
+ sizeof(uint),
+ out returnLength))
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+ throw FxTrace.Exception.AsError(new Win32Exception(errorCode));
+ }
+
+ return runningInAppContainer == 1;
+ }
+
+ internal enum TOKEN_INFORMATION_CLASS : int
+ {
+ TokenUser = 1, // TOKEN_USER structure that contains the user account of the token. = 1,
+ TokenGroups, // a TOKEN_GROUPS structure that contains the group accounts associated with the token.,
+ TokenPrivileges, // a TOKEN_PRIVILEGES structure that contains the privileges of the token.,
+ TokenOwner, // a TOKEN_OWNER structure that contains the default owner security identifier (SID) for newly created objects.,
+ TokenPrimaryGroup, // a TOKEN_PRIMARY_GROUP structure that contains the default primary group SID for newly created objects.,
+ TokenDefaultDacl, // a TOKEN_DEFAULT_DACL structure that contains the default DACL for newly created objects.,
+ TokenSource, // a TOKEN_SOURCE structure that contains the source of the token. TOKEN_QUERY_SOURCE access is needed to retrieve this information.,
+ TokenType, // a TOKEN_TYPE value that indicates whether the token is a primary or impersonation token.,
+ TokenImpersonationLevel, // a SECURITY_IMPERSONATION_LEVEL value that indicates the impersonation level of the token. If the access token is not an impersonation token, the function fails.,
+ TokenStatistics, // a TOKEN_STATISTICS structure that contains various token statistics.,
+ TokenRestrictedSids, // a TOKEN_GROUPS structure that contains the list of restricting SIDs in a restricted token.,
+ TokenSessionId, // a DWORD value that indicates the Terminal Services session identifier that is associated with the token. If the token is associated with the Terminal Server console session, the session identifier is zero. If the token is associated with the Terminal Server client session, the session identifier is nonzero. In a non-Terminal Services environment, the session identifier is zero. If TokenSessionId is set with SetTokenInformation, the application must have the Act As Part Of the Operating System privilege, and the application must be enabled to set the session ID in a token.
+ TokenGroupsAndPrivileges, // a TOKEN_GROUPS_AND_PRIVILEGES structure that contains the user SID, the group accounts, the restricted SIDs, and the authentication ID associated with the token.,
+ TokenSessionReference, // Reserved,
+ TokenSandBoxInert, // a DWORD value that is nonzero if the token includes the SANDBOX_INERT flag.,
+ TokenAuditPolicy,
+ TokenOrigin, // a TOKEN_ORIGIN value. If the token resulted from a logon that used explicit credentials, such as passing a name, domain, and password to the LogonUser function, then the TOKEN_ORIGIN structure will contain the ID of the logon session that created it. If the token resulted from network authentication, such as a call to AcceptSecurityContext or a call to LogonUser with dwLogonType set to LOGON32_LOGON_NETWORK or LOGON32_LOGON_NETWORK_CLEARTEXT, then this value will be zero.
+ TokenElevationType,
+ TokenLinkedToken,
+ TokenElevation,
+ TokenHasRestrictions,
+ TokenAccessInformation,
+ TokenVirtualizationAllowed,
+ TokenVirtualizationEnabled,
+ TokenIntegrityLevel,
+ TokenUIAccess,
+ TokenMandatoryPolicy,
+ TokenLogonSid,
+ TokenIsAppContainer,
+ TokenCapabilities,
+ TokenAppContainerSid,
+ TokenAppContainerNumber,
+ TokenUserClaimAttributes,
+ TokenDeviceClaimAttributes,
+ TokenRestrictedUserClaimAttributes,
+ TokenRestrictedDeviceClaimAttributes,
+ TokenDeviceGroups,
+ TokenRestrictedDeviceGroups,
+ MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum
+ }
+
+ internal sealed class SafeCloseHandle : SafeHandleZeroOrMinusOneIsInvalid
+ {
+ SafeCloseHandle() : base(true) { }
+ internal SafeCloseHandle(IntPtr handle, bool ownsHandle) : base(ownsHandle)
+ {
+ SetHandle(handle);
+ }
+
+ protected override bool ReleaseHandle()
+ {
+ return CloseHandle(handle);
+ }
+
+ [DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
+ extern static bool CloseHandle(IntPtr handle);
+ }
}
}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSEnvironmentHelper.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSEnvironmentHelper.cs
new file mode 100644
index 00000000000..3a7b28350ea
--- /dev/null
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSEnvironmentHelper.cs
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime;
+
+namespace System.ServiceModel
+{
+ static class OSEnvironmentHelper
+ {
+ private static readonly OSVersion s_currentVersion;
+ private static readonly byte s_currentServicePack;
+
+ static OSEnvironmentHelper()
+ {
+ s_currentServicePack = (byte)Environment.OSVersion.Version.MajorRevision;
+
+ int major = Environment.OSVersion.Version.Major;
+ int minor = Environment.OSVersion.Version.Minor;
+
+ if ((major < 5) || ((major == 5) && (minor == 0)))
+ {
+ s_currentVersion = OSVersion.PreWinXP;
+ }
+ if ((major == 5) && (minor == 1))
+ {
+ s_currentVersion = OSVersion.WinXP;
+ }
+ else if ((major == 5) && (minor == 2))
+ {
+ s_currentVersion = OSVersion.Win2003;
+ }
+ else if ((major == 6) && (minor == 0))
+ {
+ s_currentVersion = OSVersion.WinVista;
+ }
+ else if ((major == 6) && (minor == 1))
+ {
+ s_currentVersion = OSVersion.Win7;
+ }
+ else if ((major == 6) && (minor == 2))
+ {
+ s_currentVersion = OSVersion.Win8;
+ }
+ else if ((major > 6) ||
+ ((major == 6) && (minor > 2)))
+ {
+ s_currentVersion = OSVersion.PostWin8;
+ }
+ else
+ {
+ // This should only be possible if major == 5 and minor > 2
+ Fx.Assert(false, "Unknown OS");
+ s_currentVersion = OSVersion.Unknown;
+ }
+
+ }
+
+ internal static bool IsVistaOrGreater
+ {
+ get
+ {
+ return IsAtLeast(OSVersion.WinVista);
+ }
+ }
+
+ internal static bool IsApplicationTargeting45
+ {
+ get
+ {
+#pragma warning disable 0618
+ return System.Net.WebSockets.WebSocket.IsApplicationTargeting45();
+#pragma warning restore 0618
+ }
+ }
+
+ internal static int ProcessorCount
+ {
+ get
+ {
+ return Environment.ProcessorCount;
+ }
+ }
+
+ internal static bool IsAtLeast(OSVersion version)
+ {
+ return IsAtLeast(version, 0);
+ }
+
+ static bool IsAtLeast(OSVersion version, byte servicePack)
+ {
+ Fx.Assert(version != OSVersion.Unknown, "Unknown OS");
+
+ if (servicePack == 0)
+ {
+ return version <= s_currentVersion;
+ }
+
+ // If a SP value is provided and we have the same OS version, compare SP values
+ if (version == s_currentVersion)
+ {
+ return servicePack <= s_currentServicePack;
+ }
+
+ return version < s_currentVersion;
+ }
+ }
+}
diff --git a/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSVersion.cs b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSVersion.cs
new file mode 100644
index 00000000000..8146b42698d
--- /dev/null
+++ b/src/System.ServiceModel.NetNamedPipe/src/System/ServiceModel/OSVersion.cs
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.ServiceModel
+{
+ enum OSVersion
+ {
+ ///
+ /// Used when unable to determine the OS Version
+ ///
+ Unknown,
+
+ ///
+ /// OS Versions before WinXP
+ ///
+ PreWinXP,
+
+ ///
+ /// OS Version - Windows XP
+ ///
+ WinXP,
+
+ ///
+ /// OS Version - Windows Server 2003
+ ///
+ Win2003,
+
+ ///
+ /// OS Version - Windows Vista
+ ///
+ WinVista,
+
+ ///
+ /// OS Version - Windows 7
+ ///
+ Win7,
+
+ ///
+ /// OS Version - Windows 8
+ ///
+ Win8,
+
+ ///
+ /// OS Versions after Windows 8
+ ///
+ PostWin8,
+ }
+}
diff --git a/src/System.ServiceModel.NetNamedPipe/tests/NetNamedPipeBindingTest.cs b/src/System.ServiceModel.NetNamedPipe/tests/NetNamedPipeBindingTest.cs
index 759bcbf9f9d..57f4983cf3c 100644
--- a/src/System.ServiceModel.NetNamedPipe/tests/NetNamedPipeBindingTest.cs
+++ b/src/System.ServiceModel.NetNamedPipe/tests/NetNamedPipeBindingTest.cs
@@ -18,7 +18,13 @@ public static void AppContextSwitch_useSha1InPipeConnectionGetHashAlgorithm()
{
Type t = Assembly.GetAssembly(typeof(NamedPipeTransportBindingElement))
.GetType(typeof(NamedPipeTransportBindingElement).Namespace + ".PipeUri");
- MethodInfo m = t.GetMethod("BuildSharedMemoryName", BindingFlags.Static | BindingFlags.Public);
+ MethodInfo m = t.GetMethod(
+ "BuildSharedMemoryName",
+ BindingFlags.Static | BindingFlags.Public,
+ binder: null,
+ types: new Type[] { typeof(string), typeof(string), typeof(bool) },
+ modifiers: null
+ );
//swtich on
AppContext.SetSwitch("Switch.System.ServiceModel.UseSha1InPipeConnectionGetHashAlgorithm", true);