private void BeginSend(TcpKsiServiceAsyncResult asyncResult) { if (asyncResult == null) { return; } try { if (!_waitSocketConnectHandle.WaitOne(_requestTimeOut)) { Logger.Debug("Request timed out. Waiting _waitSocketConnectHandle in BeginSend timed out."); throw new KsiServiceProtocolException("Request timed out."); } Logger.Debug("Starting sending (request id: {0}).", asyncResult.RequestId); if (!asyncResult.IsCompleted) { if (_socket == null) { // stop sending if socket is closed meanwhile Logger.Debug("Stopping sending. No socket. (request id: {0}).", asyncResult.RequestId); } else { _socket.BeginSend(asyncResult.PostData, 0, asyncResult.PostData.Length, 0, SendCallback, asyncResult); } } } catch (Exception e) { SetError(asyncResult, e, "Failed to start sending."); } }
/// <summary> /// Add new async result into the collection /// </summary> /// <param name="key">The key of the element to add</param> /// <param name="asyncResult">Asycn result to add</param> public void Add(ulong key, TcpKsiServiceAsyncResult asyncResult) { lock (_syncObj) { _list.Add(key, asyncResult); } }
private void SetError(Exception e, string errorMessage) { // Wait until making a new request, retrying or disposing is in progress lock (_syncObject) { try { Logger.Debug(errorMessage + Environment.NewLine + e + Environment.NewLine + "Closing socket due to error."); CloseSocket(); // no specific asyncResult, notify all pending requests about the error foreach (ulong key in _asyncResults.GetKeys()) { TcpKsiServiceAsyncResult asyncResult = _asyncResults.GetValue(key); // If an error already exists then do not overwrite. if (asyncResult.Error != null) { continue; } asyncResult.Error = new KsiServiceProtocolException(errorMessage, e); asyncResult.SetComplete(); } Logger.Debug("Clearing asyncResults."); _asyncResults.Clear(); } catch (Exception ex) { Logger.Debug("SetError failed.", ex); throw; } } }
/// <summary> /// Remove async result from the collection /// </summary> /// <param name="asyncResult">Async result to removed</param> public void Remove(TcpKsiServiceAsyncResult asyncResult) { lock (_syncObj) { if (_list.ContainsKey(asyncResult.RequestId)) { _list.Remove(asyncResult.RequestId); } } }
/// <summary> /// End TCP request /// </summary> /// <param name="ar">TCP KSI service async result</param> /// <returns></returns> protected byte[] EndRequest(IAsyncResult ar) { TcpKsiServiceAsyncResult asyncResult = ar as TcpKsiServiceAsyncResult; if (asyncResult == null) { throw new KsiServiceProtocolException("Invalid IAsyncResult."); } try { if (_isDisposed) { throw new KsiServiceProtocolException("TCP KSI service protocol is disposed."); } if (asyncResult.IsDisposed) { throw new KsiServiceProtocolException("Provided async result is already disposed. Possibly using the same async result twice when ending request."); } if (!asyncResult.IsCompleted) { if (!asyncResult.AsyncWaitHandle.WaitOne(_requestTimeOut)) { Logger.Debug("Request timed out. Waiting asyncResult.AsyncWaitHandle in EndRequest timed out."); throw new KsiServiceProtocolException("Request timed out."); } } if (asyncResult.HasError) { Logger.Warn("{0} (request id: {1}){2}{3}", asyncResult.Error.Message, asyncResult.RequestId, Environment.NewLine, asyncResult.Error); throw asyncResult.Error; } Logger.Debug("TCP service protocol returning {0} bytes (request id: {1}).", asyncResult.ResultStream.Length, asyncResult.RequestId); return(asyncResult.ResultStream.ToArray()); } finally { asyncResult.Dispose(); } }
private void SetError(TcpKsiServiceAsyncResult asyncResult, Exception e, string errorMessage) { try { // If an error already exists then do not overwrite. if (asyncResult.Error != null) { return; } asyncResult.Error = new KsiServiceProtocolException(errorMessage, e); asyncResult.SetComplete(); _asyncResults.Remove(asyncResult); } catch (Exception ex) { Logger.Debug("SetError with asyncResult failed.", ex); throw; } }
private void SendCallback(IAsyncResult ar) { TcpKsiServiceAsyncResult asyncResult = (TcpKsiServiceAsyncResult)ar.AsyncState; if (asyncResult.IsCompleted) { return; } try { int bytesSent = _socket.EndSend(ar); Logger.Debug("{0} bytes sent to server (request id: {1}).", bytesSent, asyncResult.RequestId); } catch (Exception e) { SetError(asyncResult, e, "Failed to complete sending."); } }
private void EndBeginRequestCallback(object state, bool timedOut) { try { TcpKsiServiceAsyncResult asyncResult = (TcpKsiServiceAsyncResult)state; _asyncResults.Remove(asyncResult); if (timedOut) { asyncResult.Error = new KsiServiceProtocolException("Request timed out."); } asyncResult.SetComplete(); } catch (Exception ex) { Logger.Debug("EndBeginRequestCallback failed.", ex); throw; } }
/// <summary> /// Begin TCP request /// </summary> /// <param name="requestType"></param> /// <param name="data">request bytes</param> /// <param name="requestId">request id</param> /// <param name="callback">callback when request is finished</param> /// <param name="asyncState">async state object</param> /// <returns></returns> protected IAsyncResult BeginRequest(KsiServiceRequestType requestType, byte[] data, ulong requestId, AsyncCallback callback, object asyncState) { if (_isDisposed) { throw new KsiServiceProtocolException("TCP KSI service protocol is disposed."); } if (data == null) { throw new ArgumentNullException(nameof(data)); } TcpKsiServiceAsyncResult asyncResult = new TcpKsiServiceAsyncResult(requestType, data, requestId, callback, asyncState); Logger.Debug("Begin TCP request (request id: {0}).", asyncResult.RequestId); // Wait until retrying, disposing or error throwing is in progress lock (_syncObject) { _asyncResults.Add(requestId, asyncResult); } if (_socket == null) { CreateSocketAndConnect(); } // Before starting sending request check that other request (possibly failed) haven't finished and disposed the async result. if (!asyncResult.IsDisposed) { ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, EndBeginRequestCallback, asyncResult, _requestTimeOut, true); BeginSend(asyncResult); } return(asyncResult); }
/// <summary> /// Returns asyncResults according to response payload. /// If aggregation response payload then return asyncResult by request id. /// If error payload then return all asyncResults. /// If config response payload the return all asyncResults created by config requests. /// </summary> /// <param name="payloadInfo">Response payload info</param> /// <returns></returns> private List <TcpKsiServiceAsyncResult> GetAsyncResults(KsiServiceResponsePayloadInfo payloadInfo) { List <TcpKsiServiceAsyncResult> list = new List <TcpKsiServiceAsyncResult>(); ulong[] keys = _asyncResults.GetKeys(); switch (payloadInfo.ResponsePayloadType) { case KsiServiceResponsePayloadType.Aggregation: case KsiServiceResponsePayloadType.Extending: foreach (ulong key in keys) { if (key == payloadInfo.RequestId) { TcpKsiServiceAsyncResult asyncResult = _asyncResults.GetValue(key); if (asyncResult == null) { continue; } list.Add(asyncResult); } } break; case KsiServiceResponsePayloadType.AggregatorConfig: // return all async results of all aggregator configuration requests foreach (ulong key in keys) { TcpKsiServiceAsyncResult asyncResult = _asyncResults.GetValue(key); if (asyncResult?.ServiceRequestType == KsiServiceRequestType.AggregatorConfig) { list.Add(asyncResult); } } break; case KsiServiceResponsePayloadType.ExtenderConfig: // return all async results of all extender configuration requests foreach (ulong key in keys) { TcpKsiServiceAsyncResult asyncResult = _asyncResults.GetValue(key); if (asyncResult?.ServiceRequestType == KsiServiceRequestType.ExtenderConfig) { list.Add(asyncResult); } } break; case KsiServiceResponsePayloadType.Error: foreach (ulong key in keys) { TcpKsiServiceAsyncResult asyncResult = _asyncResults.GetValue(key); if (asyncResult != null) { list.Add(asyncResult); } } break; default: throw new KsiServiceProtocolException("Unhandled payload type."); } return(list); }