88using System . Net ;
99using System . Net . Http ;
1010using System . Net . Http . Headers ;
11+ using System . Runtime . InteropServices ;
1112using System . Text ;
1213using System . Threading ;
1314using System . Threading . Tasks ;
@@ -27,9 +28,15 @@ public abstract class HttpRequestor : IDisposable
2728
2829 static HttpRequestor ( )
2930 {
30- ServicePointManager . SecurityProtocol = ServicePointManager . SecurityProtocol | SecurityProtocolType . Tls12 ;
31- ServicePointManager . DefaultConnectionLimit = Environment . ProcessorCount ;
32- availableConnections = new SemaphoreSlim ( ServicePointManager . DefaultConnectionLimit ) ;
31+ /* If machine.config is locked, then initializing ServicePointManager will fail and be unrecoverable.
32+ * Machine.config locking is typically very brief (~1ms by the antivirus scanner) so we can attempt to lock
33+ * it ourselves (by opening it for read) *beforehand and briefly wait if it's locked */
34+ using ( var machineConfigLock = GetMachineConfigLock ( ) )
35+ {
36+ ServicePointManager . SecurityProtocol = ServicePointManager . SecurityProtocol | SecurityProtocolType . Tls12 ;
37+ ServicePointManager . DefaultConnectionLimit = Environment . ProcessorCount ;
38+ availableConnections = new SemaphoreSlim ( ServicePointManager . DefaultConnectionLimit ) ;
39+ }
3340 }
3441
3542 protected HttpRequestor ( ITracer tracer , RetryConfig retryConfig , Enlistment enlistment )
@@ -329,5 +336,28 @@ private static bool TryGetResponseMessageFromHttpRequestException(HttpRequestExc
329336 return true ;
330337
331338 }
339+
340+ private static FileStream GetMachineConfigLock ( )
341+ {
342+ var machineConfigLocation = RuntimeEnvironment . SystemConfigurationFile ;
343+ var tries = 0 ;
344+ var maxTries = 3 ;
345+ while ( tries ++ < maxTries )
346+ {
347+ try
348+ {
349+ /* Opening with FileShare.Read will fail if another process (eg antivirus) has opened the file for write,
350+ but will still let ServicePointManager read the file.*/
351+ FileStream stream = File . Open ( machineConfigLocation , FileMode . Open , FileAccess . Read , FileShare . Read ) ;
352+ return stream ;
353+ }
354+ catch ( IOException e ) when ( ( uint ) e . HResult == 0x80070020 ) // SHARING_VIOLATION
355+ {
356+ Thread . Sleep ( 10 ) ;
357+ }
358+ }
359+ /* Couldn't get the lock - the process will likely fail. */
360+ return null ;
361+ }
332362 }
333363}
0 commit comments