From 4d473b8328b6072575be43775d2d402a403e3a75 Mon Sep 17 00:00:00 2001 From: Friedrich von Never Date: Thu, 16 Mar 2017 22:44:18 +0700 Subject: [PATCH] #83: fixes in ZlibStream, XEP25Socket, KerbProcessor --- src/JabberNet/JabberNet.csproj | 8 + src/JabberNet/bedrock/io/ZlibStream.cs | 154 ++---------------- src/JabberNet/bedrock/net/XEP25Socket.cs | 130 +++++++-------- .../jabber/connection/sasl/KerbProcessor.cs | 26 +-- 4 files changed, 99 insertions(+), 219 deletions(-) diff --git a/src/JabberNet/JabberNet.csproj b/src/JabberNet/JabberNet.csproj index 2d95365..0e8545c 100644 --- a/src/JabberNet/JabberNet.csproj +++ b/src/JabberNet/JabberNet.csproj @@ -12,11 +12,19 @@ Copyright (c) Cursive, Inc. 2000—2008; Jabber-Net Contributors, 2008—2017 + + True + + + + + + diff --git a/src/JabberNet/bedrock/io/ZlibStream.cs b/src/JabberNet/bedrock/io/ZlibStream.cs index 63c5960..e7101b8 100644 --- a/src/JabberNet/bedrock/io/ZlibStream.cs +++ b/src/JabberNet/bedrock/io/ZlibStream.cs @@ -14,6 +14,8 @@ using System; using System.IO; +using System.Threading; +using System.Threading.Tasks; using ComponentAce.Compression.Libs.zlib; namespace JabberNet.bedrock.io @@ -21,7 +23,7 @@ namespace JabberNet.bedrock.io /// /// Compression failed. /// - public class CompressionFailedException : ApplicationException + public class CompressionFailedException : Exception { /// /// @@ -161,16 +163,7 @@ public override long Position set { throw new NotImplementedException("The method or operation is not implemented."); } } - /// - /// Start an async read. Implemented locally, since Stream.BeginRead() isn't really asynch. - /// - /// - /// - /// - /// - /// - /// - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (count <= 0) throw new ArgumentException("Can't read 0 bytes", "count"); @@ -181,23 +174,10 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy if (m_in.avail_in == 0) { m_in.next_in_index = 0; - return m_stream.BeginRead(m_inbuf, 0, bufsize, callback, state); + return m_stream.ReadAsync(m_inbuf, 0, bufsize, cancellationToken); } - ZlibStreamAsyncResult ar = new ZlibStreamAsyncResult(state); - callback(ar); - return ar; - } - /// - /// Complete a pending read, when the callback passed to BeginRead fires. - /// - /// - /// - public override int EndRead(IAsyncResult asyncResult) - { - if (!(asyncResult is ZlibStreamAsyncResult)) - m_in.avail_in = m_stream.EndRead(asyncResult); - return Inflate(); + return Task.FromResult(Inflate()); } /// @@ -260,17 +240,7 @@ public override void SetLength(long value) throw new NotImplementedException("The method or operation is not implemented."); } - /// - /// Begin an asynch write, compressing first. Implemented locally, since Stream.BeginWrite isn't asynch. - /// Note: may call Write() on the underlying stream more than once. - /// - /// - /// - /// - /// - /// - /// - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (count <= 0) throw new ArgumentException("Can't write 0 bytes", "count"); @@ -286,31 +256,20 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As { if (err != zlibConst.Z_OK) { - ZlibStreamAsyncResult res = new ZlibStreamAsyncResult(state, new CompressionFailedException("Compress failed: " + err)); - callback(res); - return res; + throw new CompressionFailedException("Compress failed: " + err); } } if (m_out.avail_in == 0) - return m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, callback, state); + await m_stream.WriteAsync(m_outbuf, 0, bufsize - m_out.avail_out, cancellationToken); else - return m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, new AsyncCallback(IntermediateWrite), new ZlibState(callback, state)); - } - - private void IntermediateWrite(IAsyncResult asyncResult) - { - ZlibState state = (ZlibState)asyncResult.AsyncState; - try { - m_stream.EndWrite(asyncResult); - } - catch (Exception e) - { - ZlibStreamAsyncResult res = new ZlibStreamAsyncResult(state.state, e); - state.callback(res); - return; + await m_stream.WriteAsync(m_outbuf, 0, bufsize - m_out.avail_out, cancellationToken); + await IntermediateWrite(cancellationToken); } + } + private async Task IntermediateWrite(CancellationToken cancellationToken) + { m_out.next_out_index = 0; m_out.avail_out = bufsize; int err = m_out.deflate(m_flush); @@ -318,32 +277,16 @@ private void IntermediateWrite(IAsyncResult asyncResult) { if (err != zlibConst.Z_OK) { - ZlibStreamAsyncResult res = new ZlibStreamAsyncResult(state.state, new CompressionFailedException("Compress failed: " + err)); - state.callback(res); - return; + throw new CompressionFailedException("Compress failed: " + err); } } if (m_out.avail_in == 0) - m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, state.callback, state.state); + await m_stream.WriteAsync(m_outbuf, 0, bufsize - m_out.avail_out, cancellationToken); else - m_stream.BeginWrite(m_outbuf, 0, bufsize - m_out.avail_out, new AsyncCallback(IntermediateWrite), state); - } - - /// - /// Complete a pending write, when the callback given to BeginWrite is called. - /// - /// - public override void EndWrite(IAsyncResult asyncResult) - { - if (asyncResult is ZlibStreamAsyncResult) { - ZlibStreamAsyncResult ar = (ZlibStreamAsyncResult)asyncResult; - if (ar.Exception != null) - throw ar.Exception; + await m_stream.WriteAsync(m_outbuf, 0, bufsize - m_out.avail_out, cancellationToken); + await IntermediateWrite(cancellationToken); } - else - m_stream.EndWrite(asyncResult); - return; } /// @@ -373,66 +316,5 @@ public override void Write(byte[] buffer, int offset, int count) m_stream.Write(m_outbuf, 0, bufsize - m_out.avail_out); } } - - private class ZlibStreamAsyncResult : IAsyncResult - { - private object m_state = null; - private Exception m_exception; - - public ZlibStreamAsyncResult(object state) - { - m_state = state; - } - - public ZlibStreamAsyncResult(object state, Exception except) - { - m_state = state; - m_exception = except; - } - - public Exception Exception - { - get { return m_exception; } - } - - #region IAsyncResult Members - - public object AsyncState - { - get { return m_state; } - } - - public System.Threading.WaitHandle AsyncWaitHandle - { - get - { - throw new Exception("The method or operation is not implemented."); - } - } - - public bool CompletedSynchronously - { - get { return true; } - } - - public bool IsCompleted - { - get { return true; } - } - - #endregion - } - - private class ZlibState - { - public AsyncCallback callback; - public object state; - - public ZlibState(AsyncCallback callback, object state) - { - this.callback = callback; - this.state = state; - } - } } } diff --git a/src/JabberNet/bedrock/net/XEP25Socket.cs b/src/JabberNet/bedrock/net/XEP25Socket.cs index e0e1c09..b99b432 100644 --- a/src/JabberNet/bedrock/net/XEP25Socket.cs +++ b/src/JabberNet/bedrock/net/XEP25Socket.cs @@ -1,4 +1,4 @@ -/* -------------------------------------------------------------------------- +/* -------------------------------------------------------------------------- * Copyrights * * Portions created by or assigned to Cursive Systems, Inc. are @@ -17,6 +17,7 @@ using System.Diagnostics; using System.IO; using System.Net; +using System.Net.Http; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -45,9 +46,8 @@ public XEP25Exception(string reason) : base(reason) public class XEP25Socket : BaseSocket, IHttpSocket { private const string CONTENT_TYPE = "application/x-www-form-urlencoded"; - private const string METHOD = "POST"; - private readonly RandomNumberGenerator s_rng = RNGCryptoServiceProvider.Create(); + private readonly RandomNumberGenerator s_rng = RandomNumberGenerator.Create(); private readonly Queue m_writeQ = new Queue(); private readonly Object m_lock = new Object(); @@ -61,9 +61,8 @@ public class XEP25Socket : BaseSocket, IHttpSocket private int m_curKey = 511; private bool m_running = false; private string m_id = null; - private WebProxy m_proxy = null; + private IWebProxy m_proxy = null; private X509Certificate m_cert = null; - private X509Certificate m_remote_cert = null; /// /// Do trust all server sertificates? @@ -122,7 +121,7 @@ public int NumKeys /// Proxy information. My guess is if you leave this null, the IE proxy /// info may be used. Not tested. /// - public WebProxy Proxy + public IWebProxy Proxy { get { return m_proxy; } set { m_proxy = value; } @@ -137,15 +136,6 @@ public X509Certificate LocalCertificate set { m_cert = value; } } - /// - /// The remote certificate. - /// - public X509Certificate RemoteCertificate - { - get { return m_remote_cert; } - set { m_remote_cert = value; } - } - /// /// Accept a socket. Not implemented. /// @@ -290,14 +280,32 @@ private void PollThread() m_id = null; MemoryStream ms = new MemoryStream(); - CookieContainer cookies = new CookieContainer(5); + CookieContainer cookies = new CookieContainer(); byte[] readbuf = new byte[1024]; - Stream rs; byte[] buf; - HttpWebResponse resp; - HttpWebRequest req; - Stream s; + HttpResponseMessage response; + var handler = new HttpClientHandler + { + CookieContainer = cookies, + Proxy = m_proxy, + ServerCertificateCustomValidationCallback = ValidateRemoteCertificate + }; + if (m_cert != null) + handler.ClientCertificates.Add(m_cert); + var client = new HttpClient(handler) + { + DefaultRequestHeaders = + { + ConnectionClose = true, + CacheControl = + { + NoCache = true, + NoStore = true + } + } + }; + WriteBuf start; while (m_running) @@ -344,59 +352,41 @@ private void PollThread() } POLL: - req = (HttpWebRequest)WebRequest.Create(m_url); - req.CookieContainer = cookies; - req.ContentType = CONTENT_TYPE; - req.Method = METHOD; - - if (m_cert != null) - req.ClientCertificates.Add(m_cert); - - req.KeepAlive = false; - - req.CachePolicy = new System.Net.Cache.HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.NoCacheNoStore); - req.CachePolicy = new System.Net.Cache.HttpRequestCachePolicy(System.Net.Cache.HttpRequestCacheLevel.NoCacheNoStore); - - if (m_proxy != null) - req.Proxy = m_proxy; - req.ContentLength = count; - - - try + using (var requestStream = new MemoryStream()) { - ServicePointManager.ServerCertificateValidationCallback = - ValidateRemoteCertificate; - - s = req.GetRequestStream(); - s.Write(start.buf, start.offset, start.len); - - m_remote_cert = req.ServicePoint.Certificate; - - buf = ms.ToArray(); - s.Write(buf, 0, buf.Length); - s.Close(); + var message = new HttpRequestMessage(HttpMethod.Post, m_url) + { + Content = new StreamContent(requestStream) + { + Headers = { ContentLength = count } + } + }; - resp = (HttpWebResponse) req.GetResponse(); - } - catch (WebException ex) - { - if (ex.Status != WebExceptionStatus.KeepAliveFailure) + try + { + requestStream.Write(start.buf, start.offset, start.len); + response = client.SendAsync(message).Result; + buf = ms.ToArray(); + requestStream.Write(buf, 0, buf.Length); + } + catch (WebException ex) { - m_listener.OnError(this, ex); - return; + if (ex.Status != WebExceptionStatus.KeepAliveFailure) + { + m_listener.OnError(this, ex); + return; + } + goto POLL; } - goto POLL; } - - - if (resp.StatusCode != HttpStatusCode.OK) + if (response.StatusCode != HttpStatusCode.OK) { - m_listener.OnError(this, new WebException("Invalid HTTP return code: " + resp.StatusCode)); + m_listener.OnError(this, new WebException("Invalid HTTP return code: " + response.StatusCode)); return; } - CookieCollection cc = resp.Cookies; + CookieCollection cc = cookies.GetCookies(new Uri(m_url)); Debug.Assert(cc != null); Cookie c = cc["ID"]; @@ -441,15 +431,15 @@ private void PollThread() } ms.SetLength(0); - rs = resp.GetResponseStream(); - - - int readlen; - while ((readlen = rs.Read(readbuf, 0, readbuf.Length)) > 0) + using (var rs = response.Content.ReadAsStreamAsync().Result) { - ms.Write(readbuf, 0, readlen); + int readlen; + while ((readlen = rs.Read(readbuf, 0, readbuf.Length)) > 0) + { + ms.Write(readbuf, 0, readlen); + } } - rs.Close(); + if (ms.Length > 0) { buf = ms.ToArray(); diff --git a/src/JabberNet/jabber/connection/sasl/KerbProcessor.cs b/src/JabberNet/jabber/connection/sasl/KerbProcessor.cs index ccc1603..e4ac9de 100644 --- a/src/JabberNet/jabber/connection/sasl/KerbProcessor.cs +++ b/src/JabberNet/jabber/connection/sasl/KerbProcessor.cs @@ -1,4 +1,4 @@ -/* -------------------------------------------------------------------------- +/* -------------------------------------------------------------------------- * Copyrights * * Portions created by or assigned to Cursive Systems, Inc. are @@ -427,7 +427,7 @@ internal class SSPIHelper bool _bGotClientCredentials = false; - [DllImport("secur32", CharSet = CharSet.Auto)] + [DllImport("secur32", CharSet = CharSet.Unicode)] static extern uint AcquireCredentialsHandle( string pszPrincipal, //SEC_CHAR* string pszPackage, //SEC_CHAR* //"Kerberos","NTLM","Negotiative" @@ -439,7 +439,7 @@ static extern uint AcquireCredentialsHandle( ref SECURITY_HANDLE phCredential, //SecHandle //PCtxtHandle ref ref SECURITY_INTEGER ptsExpiry); //PTimeStamp //TimeStamp ref - [DllImport("secur32", CharSet = CharSet.Auto)] + [DllImport("secur32", CharSet = CharSet.Unicode)] static extern uint AcquireCredentialsHandle( string pszPrincipal, //SEC_CHAR* string pszPackage, //SEC_CHAR* //"Kerberos","NTLM","Negotiative" @@ -451,7 +451,7 @@ static extern uint AcquireCredentialsHandle( ref SECURITY_HANDLE phCredential, //SecHandle //PCtxtHandle ref ref SECURITY_INTEGER ptsExpiry); //PTimeStamp //TimeStamp ref - [DllImport("secur32", CharSet = CharSet.Auto, SetLastError = true)] + [DllImport("secur32", CharSet = CharSet.Unicode, SetLastError = true)] static extern uint InitializeSecurityContext( ref SECURITY_HANDLE phCredential,//PCredHandle IntPtr phContext, //PCtxtHandle @@ -466,7 +466,7 @@ static extern uint InitializeSecurityContext( out uint pfContextAttr, //managed ulong == 64 bits!!! out SECURITY_INTEGER ptsExpiry); //PTimeStamp - [DllImport("secur32", CharSet = CharSet.Auto, SetLastError = true)] + [DllImport("secur32", CharSet = CharSet.Unicode, SetLastError = true)] static extern uint InitializeSecurityContext( ref SECURITY_HANDLE phCredential,//PCredHandle ref SECURITY_HANDLE phContext, //PCtxtHandle @@ -482,7 +482,7 @@ static extern uint InitializeSecurityContext( out SECURITY_INTEGER ptsExpiry); //PTimeStamp /* - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] static extern int AcceptSecurityContext(ref SECURITY_HANDLE phCredential, IntPtr phContext, ref SecBufferDesc pInput, @@ -493,7 +493,7 @@ static extern int AcceptSecurityContext(ref SECURITY_HANDLE phCredential, out uint pfContextAttr, //managed ulong == 64 bits!!! out SECURITY_INTEGER ptsTimeStamp); - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] static extern int AcceptSecurityContext(ref SECURITY_HANDLE phCredential, ref SECURITY_HANDLE phContext, ref SecBufferDesc pInput, @@ -505,33 +505,33 @@ static extern int AcceptSecurityContext(ref SECURITY_HANDLE phCredential, out SECURITY_INTEGER ptsTimeStamp); */ - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int ImpersonateSecurityContext(ref SECURITY_HANDLE phContext); - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int QueryContextAttributes(ref SECURITY_HANDLE phContext, uint ulAttribute, out SecPkgContext_Sizes pContextAttributes); - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int EncryptMessage(ref SECURITY_HANDLE phContext, uint fQOP, //managed ulong == 64 bits!!! ref SecBufferDesc pMessage, uint MessageSeqNo); //managed ulong == 64 bits!!! - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int DecryptMessage(ref SECURITY_HANDLE phContext, ref SecBufferDesc pMessage, uint MessageSeqNo, out uint pfQOP); - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int MakeSignature(ref SECURITY_HANDLE phContext, // Context to use uint fQOP, // Quality of Protection ref SecBufferDesc pMessage, // Message to sign uint MessageSeqNo); // Message Sequence Num. - [DllImport("secur32.Dll", CharSet = CharSet.Auto, SetLastError = false)] + [DllImport("secur32.Dll", CharSet = CharSet.Unicode, SetLastError = false)] public static extern int VerifySignature(ref SECURITY_HANDLE phContext, // Context to use ref SecBufferDesc pMessage, // Message to sign uint MessageSeqNo, // Message Sequence Num.