views:

5153

answers:

13

Im attempting to write a push server for the iPhone in C#. I have the following code:

        // Create a TCP/IP client socket.
        using (TcpClient client = new TcpClient())
        {
            client.Connect("gateway.sandbox.push.apple.com", 2195);
            using (NetworkStream networkStream = client.GetStream())
            {
                Console.WriteLine("Client connected.");

                X509Certificate clientCertificate = new X509Certificate(@"certfile.p12", passwordHere);
                X509CertificateCollection clientCertificateCollection = new X509CertificateCollection(new X509Certificate[1] { clientCertificate });

                // Create an SSL stream that will close the client's stream.
                SslStream sslStream = new SslStream(
                    client.GetStream(),
                    false,
                    new RemoteCertificateValidationCallback(ValidateServerCertificate),
                    null
                    );

                try
                {
                    sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com");
                }
                catch (AuthenticationException e)
                {
                    Console.WriteLine("Exception: {0}", e.Message);
                    if (e.InnerException != null)
                    {
                        Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                    }
                    Console.WriteLine("Authentication failed - closing the connection.");
                    client.Close();
                    return;
                }
            }

ect....

Only I keep receiving a exception: "A call to SSPI failed, see Inner exception" Inner Exception -> "The message received was unexpected or badly formatted."

Does anyone have any idea whats going wrong here?

A: 

Other way is just to use X509Certificate2 and X509CertificateCollection2 classes.

A: 

Can you post your full code,

Armen Merikyan
Let me clean it up a bit and I will post a tutorial showing how this is done.
Zenox
A: 

I recently used Growl For Windows to push messages to the Prowl client on the IPhone from .Net code. So you might get your functionatlity without writing a push server yourself.

tobsen
That may work for pushing data to the apn, but what about handling the feedback though?
Zenox
A: 

Also check out this service from iLime

Leon
A: 

The "The message received was unexpected or badly formatted." error usually comes when you did not register the p12 certificate in Windows. (Under Vista, just double click on the p12 file and the import wizard will open)

+1  A: 

From Zenox's comment: use a different version of AuthenticateAsClient

sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", clientCertificateCollection, SslProtocols.Default, false);
Michael Donohue
A: 

This example was very helpful, thank you.

I receive the exception when trying to AuthenticateAsClient Message: "A call to SSPI failed, see inner exception." Inner: An unknown error occured while processing the certificate

The certificate is installed, In can read it from the Personal X509Store no problems. I wish that error was better.

Also.. would you mind posting the code you used to construct the message payload as described here? http://is.gd/1HTtd

Kevin
+4  A: 

Figured it out. Replaced sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com"); with sslStream.AuthenticateAsClient("gateway.sandbox.push.apple.com", clientCertificateCollection, SslProtocols.Default, false); And registered the certificates on the PC.

Edit: Here is the code for creating a payload as requested:

    private static byte[] GeneratePayload(byte [] deviceToken, string message, string sound)
    {
        MemoryStream memoryStream = new MemoryStream();

        // Command
        memoryStream.WriteByte(0);

        byte[] tokenLength = BitConverter.GetBytes((Int16)32);
        Array.Reverse(tokenLength);
        // device token length
        memoryStream.Write(tokenLength, 0, 2);

        // Token
        memoryStream.Write(deviceToken, 0, 32);

        // String length
        string apnMessage = string.Format ( "{{\"aps\":{{\"alert\":{{\"body\":\"{0}\",\"action-loc-key\":null}},\"sound\":\"{1}\"}}}}",
            message,
            sound);

        byte [] apnMessageLength = BitConverter.GetBytes((Int16)apnMessage.Length);
        Array.Reverse ( apnMessageLength );
        // message length
        memoryStream.Write(apnMessageLength, 0, 2);

        // Write the message
        memoryStream.Write(System.Text.ASCIIEncoding.ASCII.GetBytes(apnMessage), 0, apnMessage.Length);

        return memoryStream.ToArray();
    } // End of GeneratePayload
Zenox
What folder (Certificate Store) should I use to import to on Windows Server? Is it Personal or Trusted Publisher? I tried "Default select based on certificate type" but didnt work.
Akash Kava
+1  A: 

Leon,

Thanks for the iLime mention. For those reading this thread, we launched the Push service over the weekend at iPhoneDevCamp out in Sunnyvale. Anyone here is welcome to sign up and check out our documentation, sample code, and integrate the service into their applications.

http://www.ilime.com

Any questions, don't hesitate to ask here or to [email protected].

Best,

Tim Courtney Director, Marketing & Brand Strategy KeyLimeTie

+1  A: 

P. S. The first 25,000 pushes sent each month are free, which can be a quite cost-effective service for many apps, and helpful for testing. :-)

Best,

Tim

+1  A: 

hi guys, can anyone please post a full sample code for this? I'm not finding one anywhere :(

devguy
I would suggest using this library: http://code.google.com/p/apns-sharp/It it much better than any of the samples I previously posted here.
Zenox
A: 

Hi there,

Zenox.. I have got the same problem.. However its failing on the server.. I have installed the certification on the Local Computer -> Personal and Trusted both.. Got win2k3 running.. Is that where you installed your certificate?

The problem i am having is posted here...

http://stackoverflow.com/questions/1884959/exception-on-sslstream-authenticateasclient-the-message-was-badly-formatted

Noms
+1  A: 

Hi,

I used the above code, but my iPhone (neither of the two test devices I have) receive and display the push message.

I receive the push token from the application, sent it to our servers, and manually double-checked personally that the data is stored in our database correctly.

As for the TCP connection to apple's servers, I don't get any exceptions, and everything seems to connect correctly.

For sending the push message, in my test code (using the above example as a base), I have put in this code:

sslStream.Write( pushMessage );

and more recently I've put in:

sslStream.Write( pushMessage );
sslStream.Flush();
sslStream.Close();

basically, I get no real feedback, and the iphone doesn't get the message. How many points of failure have I overlooked? (1) ssl authentication - seems to be working, (2) developer certificate is in use, and I'm using the sandbox address on port 2195, (3) the push token has been painstakingly verified from the device and in my database...

(4) ?

any suggestions on where to even start debugging it would be appreciated.

John Kooistra
Hey John, Make sure you downloaded the development key and not the production key from apples website. Also make sure you are connecting to the sandbox server.
Zenox
You realize you're asking a question in the answer section right?
edude05