Q:

Read from Half Open Socket

I am trying to connect to Apple Push Notification Service which uses a simple binary protocol over TCP protected with TLS (or SSL). The protocol indicates that when an error is encountered (there are about 10 well defined error conditions) APNS will send back an error response and then close the connection. This results in a half closed socket because the remote peer closed the socket. I can see its a graceful shutdown because APNS sends a FIN and RST using tcpdump.
Out of all the error conditions, I can deal with most before sending with validation. The situation in which this fails is when a notification is sent to an invalid device token which cannot be dealt with that easily because the tokens could be malformed. Tokens are opaque 32 byte values that are provided by APNS to a device and then registered with me. I have no way of knowing if it is valid when submitted to my service. Presumably APNS checksums the tokens in some way that they can do quick validation on the token fast.
Anyway,
I did what I thought was the right thing:-
a.  open socket
b.  try writing
c.  if write failed, read the error response

Unfortunately, this doesn't seem to work. I figure APNS is sending an error response and I am not reading it back right or I am not setting the socket up right. I have tried the following techniques:-

Use a separate thread per socket to try-read the response if any every 5ms or so.
Use a blocking read after write failure.
Use a final read after remote disconnect.

I have tried this with C# + .NET 4.5 on Windows and Java 1.7 on Linux. In either case, I never seem to get the error response and the socket indicates that no data is available to read.
Are half-closed sockets supported on these operating systems and/or frameworks? There isn't anything that seems to indicate either way. 
I know that the way I am setting things up works correctly because if I use a valid token with a valid notification, those do get delivered. 
In response to one of the comments, I am using the enhanced notification format so a response should arrive from APNS.
Here is the code I have for C#:-
X509Certificate certificate = 
new X509Certificate(@"Foo.cer", "password");
X509CertificateCollection collection = new X509CertificateCollection();
collection.Add(certificate);

Socket socket = 
   new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("gateway.sandbox.push.apple.com", 2195);

NetworkStream stream = 
   new NetworkStream(socket, System.IO.FileAccess.ReadWrite, false);
stream.ReadTimeout = 1000;
stream.WriteTimeout = 1000;

sslStream = 
  new SslStream(stream, true, 
     new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", collection,
                               SslProtocols.Default, false);
sslStream.ReadTimeout = 10000;
sslStream.WriteTimeout = 1000;

// Task rdr = Task.Factory.StartNew(this.reader);
// rdr is used for parallel read of socket sleeping 5ms between each read.
// Not used now but another alternative that was tried.

Random r = new Random(DateTime.Now.Second);
byte[] buffer = new byte[32];
r.NextBytes(buffer);
byte[] resp = new byte[6];

String erroneousToken = toHex(buffer);

TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
int timestamp  = (int) t.TotalSeconds;

try
{
    for (int i = 0; i < 1000; ++i)
    {
        // build the notification; format is published in APNS docs.
        var not = new ApplicationNotificationBuilder().withToken(buffer).withPayload(
             @'{"aps": {"alert":"foo","sound":"default","badge":1}}').withExpiration(
                timestamp).withIdentifier(i+1).build();

        sslStream.Write(buffer);
        sslStream.Flush();
        Console.Out.WriteLine("Sent message # " + i);

        int rd = sslStream.Read(resp, 0, 6);

        if (rd > 0)
        {
            Console.Out.WriteLine("Found response: " + rd);
            break;
        }

        // doesn't really matter how fast or how slow we send
        Thread.Sleep(500);
    }
}
catch (Exception ex)
{
    Console.Out.WriteLine("Failed to write ...");

    int rd = sslStream.Read(resp, 0, 6);

    if (rd > 0)
    {
        Console.Out.WriteLine("Found response: " + rd); ;
    }
}

// rdr.Wait(); change to non-infinite timeout to allow error reader to terminate

A:

I implemented server side for APNS in Java and have problems reading the error responses reliably (meaning - never miss any error response), but I do manage to get error responses.
You can see this related question, though it has no adequate answer.
If you never manage to read the error response, there must be something wrong with your code.

Using a separate thread for reading worked for me, though not 100% reliable.
Use a blocking read after write fail - that's what Apple suggest to do, but it doesn't always work. It's possible that you send 100 messages, and the first has an invalid token, and only after the 100th message you get a write failure. At this point it is sometimes too late to read the error response from the socket.
I'm not sure what you mean there.

If you want to guarantee that the reading of the error responses will work, you should try to read after each write, with a sufficient timeout. This, of course, is not practical for using in production (since it's incredibly slow), but you can use it to verify that your code of reading and parsing the error response is correct. You can also use it to iterate over all the device tokens you have, and find all the invalid ones, in order to clean your DB.
You didn't post any code, so I don't know what binary format you are using to send messages to APNS. If you are using the simple format (that starts with a 0 byte and has no message ID), you won't get any responses from Apple.

