Search code examples
c#asp.net-mvcapple-push-notificationsapns-sharp

APNS Feedback Service C# code not working


I tried to implement a feed back service code which i found over here.

here is my code:

private X509Certificate getServerCert(string certName)
        {
            var store = new X509Store(StoreLocation.LocalMachine);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                var certs = store.Certificates.Find(X509FindType.FindBySubjectName, certName, false);
                return certs.Count == 0 ? null : certs[0];
            }
            finally
            {
                store.Close();
            }
        }

public String CheckFeedbackService(string certaName)
        {

            System.Net.ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(ValidateServerCertificate);
            KIREIP.Core.Manager.IphoneErrorLog errorLog = new KIREIP.Core.Manager.IphoneErrorLog();
            // Create an empty collection of certs
            X509Certificate2Collection certs = new X509Certificate2Collection();

            // Add the Apple cert to our collection
            certs.Add(getServerCert(certaName));

            // Apple feedback server address
            string apsHostF;

            if (getServerCert(certaName).ToString().Contains("Production"))
                apsHostF = "feedback.push.apple.com";
            else
                apsHostF = "feedback.sandbox.push.apple.com";

            // Create a TCP socket connection to the Apple server on port 2196
            TcpClient tcpClientF = new TcpClient(apsHostF, 2196);

            //Set up
            byte[] buffer = new byte[38];
            int recd = 0;
            DateTime minTimestamp = DateTime.Now.AddYears(-1);
            string result = string.Empty;

            // Create a new SSL stream over the connection
            SslStream sslStreamF = new SslStream(tcpClientF.GetStream(), true, new RemoteCertificateValidationCallback(ValidateServerCertificate));

            try
            {
                // Authenticate using the Apple cert
                sslStreamF.AuthenticateAsClient(apsHostF, certs, SslProtocols.Default, false);

                //TODO: Read in data and remove device tokens if any found.
                errorLog.AddErrorLog("Stream Readable ::" + sslStreamF.CanRead);
                //errorLog.AddErrorLog("Host Name ::" + hostName);
                errorLog.AddErrorLog("Cert Name ::" + certs[0].FriendlyName);

                if (sslStreamF != null)
                {
                    errorLog.AddErrorLog("Connection Started");

                    //Get the first feedback
                    recd = sslStreamF.Read(buffer, 0, buffer.Length);
                    errorLog.AddErrorLog("Buffer length ::" + recd);
                    //Continue while we have results and are not disposing
                    while (recd > 0)
                    {

                        errorLog.AddErrorLog("Reading Started");
                        //Get our seconds since 1970 ?
                        byte[] bSeconds = new byte[4];
                        byte[] bDeviceToken = new byte[32];
                        Array.Copy(buffer, 0, bSeconds, 0, 4);
                        //Check endianness
                        if (BitConverter.IsLittleEndian)
                            Array.Reverse(bSeconds);
                        int tSeconds = BitConverter.ToInt32(bSeconds, 0);
                        //Add seconds since 1970 to that date, in UTC and then get it locally
                        var Timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(tSeconds).ToLocalTime();
                        //Now copy out the device token
                        Array.Copy(buffer, 6, bDeviceToken, 0, 32);
                        string deviceToken = BitConverter.ToString(bDeviceToken).Replace("-", "").ToLower().Trim();
                        //Make sure we have a good feedback tuple
                        if (deviceToken.Length == 64 && Timestamp > minTimestamp)
                        {
                            errorLog.AddErrorLog("Feedback " + deviceToken);
                            result = deviceToken;
                            errorLog.AddErrorLog(result);
                        }
                        //Clear  array to reuse it
                        Array.Clear(buffer, 0, buffer.Length);
                        //Read the next feedback
                        recd = sslStreamF.Read(buffer, 0, buffer.Length);
                    }
                    errorLog.AddErrorLog("Reading Ended");
                }

                if (sslStreamF != null)
                    sslStreamF.Close();

                if (tcpClientF != null)
                    tcpClientF.Close();

            }

            catch (AuthenticationException e)
            {
                errorLog.AddErrorLog("Authentication failed - closing the connection.");
                sslStreamF.Close();
                tcpClientF.Close();
                return "NOAUTH";
            }

            finally
            {
                // The client stream will be closed with the sslStream
                // because we specified this behavior when creating
                // the sslStream.
                sslStreamF.Close();
                tcpClientF.Close();
            }

            return "";
        }

Whenever i run this code i get null value from getServerCert(certName) method, because of this null value my further execution get failed.

Any help would be greatly appreciated


Solution

  • I have used JdSoft.Apns.Feedback.dll that I found here (or you may google it directly to get latest version).

    Using this .dll I have generate the below method with 2 delegates

    public string CheckFeedBack()
            {
    
                //Variables you may need to edit:
                //---------------------------------
                //Log.AddErrorLog("Start");
                //True if you are using sandbox certificate, or false if using production
                bool sandbox = Convert.ToBoolean(System.Configuration.ConfigurationManager.AppSettings["sandbox"].ToString());
    
                //Put your PKCS12 .p12 or .pfx filename here.
                // Assumes it is in the same directory as your app
                string p12File = System.Configuration.ConfigurationManager.AppSettings["p12File"].ToString();
    
                //This is the password that you protected your p12File 
                //  If you did not use a password, set it as null or an empty string
                string p12FilePassword = System.Configuration.ConfigurationManager.AppSettings["p12FilePassword"].ToString();
    
    
                //Actual Code starts below:
                //--------------------------------
    
                //Get the filename assuming the file is in the same directory as this app
                string p12Filename = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, p12File);
                //errorLog.AddErrorLog(p12Filename);
                //Create the feedback service consumer
                FeedbackService service = new FeedbackService(sandbox, p12Filename, p12FilePassword);
    
                //Wireup the events
                service.Error += new FeedbackService.OnError(service_Error);
                service.Feedback += new FeedbackService.OnFeedback(service_Feedback);
    
                //Run it.  This actually connects and receives the feedback
                // the Feedback event will fire for each feedback object
                // received from the server
                service.Run();
                Log.AddErrorLog("Done.");
                Log.AddErrorLog("Cleaning up...");
    
                //Clean up
                service.Dispose();
    
                return "Checked database table log..";
            } 
    

    Delegates to wireup feedback and error events

                static void service_Feedback(object sender, Feedback feedback)
                {
                 Log.AddErrorLog(string.Format("Feedback - Timestamp: {0} - DeviceId: {1}", feedback.Timestamp, feedback.DeviceToken));
                 //DeviceToken retrive over here
    
                }
                static void service_Error(object sender, Exception ex)
                {
    
                 Log.AddErrorLog(string.Format("Error: {0}", ex.Message));
                 //Error Message if failed
                }