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); }
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); }