Exemplo n.º 1
0
        public IEnumerable <ApnsTokeExpirationInfo> GetTokenExpirations()
        {
            var encoding = Encoding.ASCII;

            var certificate = Configuration.Certificate;

            var certificates = new X509CertificateCollection();

            certificates.Add(certificate);

            var client = new TcpClient();

            Log.Info("APNS-FeedbackService: Connecting");
            if (Configuration.UseProxy)
            {
                var proxyHelper = new ProxyHelper {
                    ProxyConnectionExceptionCreator = (message) => new ApnsConnectionException(message)
                };
                proxyHelper.BeforeConnect += () => Log.Info("APNS-FeedbackService: Connecting Proxy");
                proxyHelper.AfterConnect  += (status) => Log.Info("APNS-FeedbackService: Proxy Connected : {0}", status);
                proxyHelper.Connect(client, Configuration.FeedbackHost, Configuration.FeedbackPort, Configuration.ProxyHost, Configuration.ProxyPort, Configuration.ProxyCredentials).Wait();
            }
            else
            {
                client.Connect(Configuration.FeedbackHost, Configuration.FeedbackPort);
            }
            Log.Info("APNS-FeedbackService: Connected");

            var stream = new SslStream(client.GetStream(), true,
                                       (sender, cert, chain, sslErrs) => { return(true); },
                                       (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return(certificate); });

            var tls = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12;

            stream.AuthenticateAsClient(Configuration.FeedbackHost, certificates, tls, false);


            //Set up
            byte[] buffer = new byte[4096];
            int    recd   = 0;
            var    data   = new List <byte>();

            Log.Info("APNS-FeedbackService: Getting expirations");

            //Get the first feedback
            recd = stream.Read(buffer, 0, buffer.Length);

            var tokenBatch = new List <ApnsTokeExpirationInfo>();

            //Continue while we have results and are not disposing
            while (recd > 0)
            {
                // Add the received data to a list buffer to work with (easier to manipulate)
                for (int i = 0; i < recd; i++)
                {
                    data.Add(buffer[i]);
                }

                //Process each complete notification "packet" available in the buffer
                while (data.Count >= (4 + 2 + 32)) // Minimum size for a valid packet
                {
                    var secondsBuffer     = data.GetRange(0, 4).ToArray();
                    var tokenLengthBuffer = data.GetRange(4, 2).ToArray();

                    // Get our seconds since epoch
                    // Check endianness and reverse if needed
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(secondsBuffer);
                    }
                    var seconds = BitConverter.ToInt32(secondsBuffer, 0);

                    //Add seconds since 1970 to that date, in UTC
                    var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(seconds);

                    //flag to allow feedback times in UTC or local, but default is local
                    if (!Configuration.FeedbackTimeIsUTC)
                    {
                        timestamp = timestamp.ToLocalTime();
                    }


                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tokenLengthBuffer);
                    }
                    var tokenLength = BitConverter.ToInt16(tokenLengthBuffer, 0);

                    if (data.Count >= 4 + 2 + tokenLength)
                    {
                        var tokenBuffer = data.GetRange(6, tokenLength).ToArray();
                        // Strings shouldn't care about endian-ness... this shouldn't be reversed
                        //if (BitConverter.IsLittleEndian)
                        //    Array.Reverse (tokenBuffer);
                        var token = BitConverter.ToString(tokenBuffer).Replace("-", "").ToLower().Trim();

                        // Remove what we parsed from the buffer
                        data.RemoveRange(0, 4 + 2 + tokenLength);

                        tokenBatch.Add(new ApnsTokeExpirationInfo(token, timestamp));
                        // Raise the event to the consumer
                        var evt = FeedbackReceived;
                        if (evt != null)
                        {
                            evt(token, timestamp);
                        }
                    }
                    else
                    {
                        continue;
                    }
                }

                //Read the next feedback
                recd = stream.Read(buffer, 0, buffer.Length);
            }

            try
            {
                stream.Close();
                stream.Dispose();
            }
            catch { }

            try
            {
                client.Client.Shutdown(SocketShutdown.Both);
                client.Client.Dispose();
            }
            catch { }

            try { client.Close(); } catch { }

            Log.Info("APNS-FeedbackService: {0} expiration(s) received.", tokenBatch.Count);
            return(tokenBatch);
        }
Exemplo n.º 2
0
        async Task connect()
        {
            if (client != null)
            {
                disconnect();
            }

            Log.Info("APNS-Client[{0}]: Connecting (Batch ID={1})", id, batchId);

            client = new TcpClient();

            try
            {
                if (!Configuration.UseProxy)
                {
                    await client.ConnectAsync(Configuration.Host, Configuration.Port).ConfigureAwait(false);
                }
                else
                {
                    var proxyHelper = new ProxyHelper {
                        ProxyConnectionExceptionCreator = (message) => new ApnsConnectionException(message)
                    };
                    proxyHelper.BeforeConnect += () => Log.Info("APNS-Client[{0}]: Connecting Proxy (Batch ID={1})", id, batchId);
                    proxyHelper.AfterConnect  += (status) => Log.Info("APNS-Client[{0}]: Proxy Connected (Batch ID={1}) : {2}", id, batchId, status);
                    await proxyHelper.Connect(client, Configuration.Host, Configuration.Port, Configuration.ProxyHost, Configuration.ProxyPort, Configuration.ProxyCredentials).ConfigureAwait(false);
                }

                //Set keep alive on the socket may help maintain our APNS connection
                try
                {
                    client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
                }
                catch
                {
                }

                //Really not sure if this will work on MONO....
                // This may help windows azure users
                try
                {
                    SetSocketKeepAliveValues(client.Client, (int)Configuration.KeepAlivePeriod.TotalMilliseconds, (int)Configuration.KeepAliveRetryPeriod.TotalMilliseconds);
                }
                catch
                {
                }
            }
            catch (ApnsConnectionException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new ApnsConnectionException("Failed to Connect, check your firewall settings!", ex);
            }

            // We can configure skipping ssl all together, ie: if we want to hit a test server
            if (Configuration.SkipSsl)
            {
                networkStream = client.GetStream();
            }
            else
            {
                // Create our ssl stream
                stream = new SslStream(client.GetStream(),
                                       false,
                                       ValidateRemoteCertificate,
                                       (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => certificate);

                try {
                    stream.AuthenticateAsClient(Configuration.Host, certificates, System.Security.Authentication.SslProtocols.Tls, false);
                } catch (System.Security.Authentication.AuthenticationException ex) {
                    throw new ApnsConnectionException("SSL Stream Failed to Authenticate as Client", ex);
                }

                if (!stream.IsMutuallyAuthenticated)
                {
                    throw new ApnsConnectionException("SSL Stream Failed to Authenticate", null);
                }

                if (!stream.CanWrite)
                {
                    throw new ApnsConnectionException("SSL Stream is not Writable", null);
                }

                networkStream = stream;
            }

            Log.Info("APNS-Client[{0}]: Connected (Batch ID={1})", id, batchId);
        }