Using HttpWebRequest to perform HTTPS post fails with strange error message

Posted on August 13th, 2008 in .NET, Vista, Windows Server 2008 by Tom

Recently, after upgrading a server to Server 2008, some developers (ok, about 15 developers and BAs) began complaining that a post to a 3rd party vendor was no longer functioning. One of the devs whipped up a winform app to test from the server and locally from his workstation. From his Windows XP workstation, it was fine. From the Server 2008 box (and from my Vista laptop) it failed to connect with:

The underlying connection was closed: An unexpected error occurred on a send.

Descriptive.

A full stack trace revealed:

System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. —> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
— End of inner exception stack trace —
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.ConnectStream.WriteHeaders(Boolean async)
The underlying connection was closed: An unexpected error occurred on a send.
at System.Net.HttpWebRequest.GetRequestStream()

Keep in mind that this worked fine on XP and 2003. Vista and 2008 always threw that exception…without exception. The code was just doing a basic XML post to an HTTPS service with authentication enabled.


ASCIIEncoding ascii = new ASCIIEncoding();
string requestToSend = body;
byte[] data = ascii.GetBytes(requestToSend);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(destination);

webRequest.Credentials = new NetworkCredential("User", "Pass");
webRequest.Method = "POST";
webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2";
webRequest.ContentType = "text/xml";
webRequest.ContentLength = data.Length;
webRequest.KeepAlive = false;                                              

//Throws an exception HERE
Stream outStream = webRequest.GetRequestStream();
outStream.Write(data, 0, data.Length);
outStream.Close();

From that stack trace, I could see that the remote server was closing the connection…but, I had no idea why. Something in how it made the request was different than XP or 2003.

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

As it turns out, the defult behavior in Vista and Server 2008 is to use TLS first for secure connections. If the server doesn’t support TLS, it’s supposed to negotiate with the client to use SSL3. In this case, the remote server wasn’t negotiating at all…It was just dropping the connection.

http://blogs.msdn.com/wndp/archive/2006/04/12/tls_enabled_by_default.aspx

Long story short:

If you upgrade to Server 2008 or Vista, and your HTTPS XML POSTs are failing due to some strange error, try to force SSL3.

How to export your IIS7 config from one server and import into another

Posted on May 27th, 2008 in IIS7, Microsoft, Windows Server 2008 by Tom

I had copied the IIS7 config files from an already-configured server to a new server I was building. The two servers were going to be load balanced (non-NLB). After overwriting the config files on the new server with those that I had exported from the old server, I discovered that my app pools kept crashing. I attempted to reset the domain account credentials on the app pools, but found myself getting:

hresult:0×80090005, Message: Failed to commit configuration. Bad Data.

Built-in account works, domain accounts did not. Given that I’m much too lazy to re-configure all of the application pool IDs, I began looking for a way to gracefully import settings from the other server. Turns out, there isn’t an “import” button, so to speak. I did find that using “Shared configuration” I could essentially accomplish an import.

In IIS manager, you need to export the config from the already-configured server. In IIS manager, click the Server node, and go to Shared Configuration under Management.

IIS Shared Configuration

Click “Export Configuration

Export Configuration

Enter the path you’d like to export the config to, and set an encryption key password:

Export Configuration Settings

Copy administration.config, applicationHost.config, and configEncKey.key to your new server to a temp location.

On the new server, go back to the “Shared Configuration” section and check “Enable shared configuration.” Enter the location in physical path and click “Apply.” It should prompt for the encryption password that you had set. Enter it, and reset IIS.

Import IIS Config

After resetting IIS, go back to Shared Configuration and uncheck “Enable shared configuration.” Click apply. You should see this:

Shared Configuration Warning

Click YES and it will import all of the settings from your Shared Config into the local config on your new IIS server.

At this point, all you should need to do is change your server-specific site bindings, and it should be good to go.

PowerShell Script for Remote Event Log Viewing

Posted on December 13th, 2007 in Microsoft, PowerShell, Server Management by Tom

I had an issue today where I needed to find the frequency of an error on some of my VMs. It seems like I get VMSCSI errors at the same time each which (which probably means high SAN activity, but I’m trying to nail everything down). Either way, I needed to check all of my event logs for EventID 11 and 15. It’s slow…and by slow I mean it took about 30 minutes to scan 10 or so VMs…but it works, and I was able to get a decent idea of the times I’m seeing these errors.

$servers = .\getservernames.ps1 Tom 
 
foreach ($server in $servers) 
{ 
     if ((get-wmiobject -computer $server win32_computersystem).manufacturer -eq "VMware, Inc.") 
     { 
         get-wmiobject -query 
            "select * from Win32_NTLogEvent where LogFile = 'System' AND EventCode = 11 
            OR EventCode = 15" | 
            foreach { add-content c:\temp\$server.log "$_.timegenerated - $_.eventcode" }
     }
}

Aaaand, it’ll return logs for each server, with a time stamp, the event ID, and nothing more. Quick, dirty, but took me 5 minutes and got the info I needed…30 minutes later :p There’s probably a better way. I’ll have to see what I can come up with.

Windows Server 2008

Posted on December 3rd, 2007 in Microsoft, Windows Server 2008 by Tom

According to this article (thanks www.ActiveWin.com for the link) at Network World, Server 2008 may flop. Why? Because 50% of IT Pros surveyed have no plans to deploy Server 2008. This is misleading. “Not having plans” doesn’t mean “won’t.” I don’t “plan” to put gas in my car within the next 12 hours, but that doesn’t mean I’m never putting gas in my car.