public ServiceProtocolAwaiter <T> SendRequest <T>(ServiceProtocolRequest request) where T : ServiceProtocolResponse, new() { if (request == null) { throw new ArgumentNullException(nameof(request)); } localThreadClient = this; requestIndex = (uint)Interlocked.Increment(ref lastRequestQueueIndex) % maxConcurrentRequests; if (Interlocked.CompareExchange(ref requestStates[requestIndex], RequestStateBeforeSend, RequestStateInactive) != RequestStateInactive) { ServiceProtocolResponse.localThreadCodeForErrorResponses = ServiceProtocolResponseCode.RequestQueueOverflow; return(ServiceProtocolAwaiter <T> .Instance); } ServiceProtocolResponse.localThreadCodeForErrorResponses = ServiceProtocolResponseCode.Success; request.id = requestIndex; Thread.MemoryBarrier(); AddToSendQueue(request); return(ServiceProtocolAwaiter <T> .Instance); }
private void AddToSendQueue(ServiceProtocolRequest request) { var newValue = Interlocked.Increment(ref requestsQueueSize); Thread.MemoryBarrier(); requestsQueue.Enqueue(request); if (newValue == 1) { Task.Run(() => Send()); } }
public void SendRequestWithoutResponse(ServiceProtocolRequest request) { if (request == null) { throw new ArgumentNullException(nameof(request)); } request.id = ServiceProtocolDataContract.RequestIdWithoutResponse; Thread.MemoryBarrier(); AddToSendQueue(request); }
private void Receive(object sender, SocketAsyncEventArgs args) { var socket = (Socket)sender; var connection = (ServiceProtocolIncomingConnection)args.UserToken; if (args.BytesTransferred == 0 || args.SocketError != SocketError.Success || listenSocket == null || connection.connectionVersion != connectionVersion) { connection.Dispose(); args.Dispose(); return; } var bytesAvailable = args.Offset + args.BytesTransferred; var offset = 0; while (true) { if (bytesAvailable < ServiceProtocolRequest.HeaderSize) { goto ContinueReceive; } ServiceProtocolRequest.ReadHeader(args.Buffer, offset, out var requestId, out var requestKind, out var requestSize); if (bytesAvailable - ServiceProtocolRequest.HeaderSize < requestSize) { goto ContinueReceive; } offset += ServiceProtocolRequest.HeaderSize; bytesAvailable -= ServiceProtocolRequest.HeaderSize; connection.unpackStream.Position = offset; if (requestKind >= dataContract.requestUnpackers.Length) { logger.Error($"Service protocol server: Received invalid request kind! Client: {socket.RemoteEndPoint}"); connection.Dispose(); args.Dispose(); return; } var unpacker = dataContract.requestUnpackers[requestKind]; if (unpacker == null) { logger.Error($"Service protocol server: Could not find request unpacker by kind {requestKind}! Client: {socket.RemoteEndPoint}"); connection.Dispose(); args.Dispose(); return; } ServiceProtocolRequest request; try { request = unpacker(connection.unpackReader); } catch (Exception e) { logger.Fatal($"Service protocol server: Could not unpack request! Kind: {requestKind} Client: {socket.RemoteEndPoint} Details: {e}"); connection.Dispose(); args.Dispose(); return; } var realUnpackedSize = (int)(connection.unpackStream.Position - offset); if (realUnpackedSize != requestSize) { logger.Error( $"Service protocol server: Could not unpack request! Kind: {requestKind} Real unpacked size not equal with size in header! Client: {socket.RemoteEndPoint}"); connection.Dispose(); args.Dispose(); return; } bytesAvailable -= requestSize; offset += requestSize; var handler = handlers[requestKind]; if (handler == null) { logger.Error($"Service protocol server: Could not find handler by type: {request.GetType()}! Client: {socket.RemoteEndPoint}"); connection.Dispose(); args.Dispose(); return; } request.id = requestId; var count = Interlocked.Increment(ref connection.concurrentRequestsCount); if (count > maxConcurrentRequestsPerClient) { logger.Error( $"Service protocol server: Client {socket.RemoteEndPoint} exceeded limit of concurrent requests - force disconnect! Limit: {maxConcurrentRequestsPerClient}"); connection.Dispose(); args.Dispose(); return; } request.connection = connection; try { handler(connection, request); } catch (Exception e) { logger.Fatal($"Service protocol server: Could not process response! Client: {socket.RemoteEndPoint} Details: {e}"); } if (request.id == ServiceProtocolDataContract.RequestIdWithoutResponse) { Interlocked.Decrement(ref connection.concurrentRequestsCount); } if (bytesAvailable == 0) { goto ContinueReceive; } } ContinueReceive: if (bytesAvailable > 0) { Array.Copy(args.Buffer, offset, args.Buffer, 0, bytesAvailable); } args.SetBuffer(bytesAvailable, args.Buffer.Length - bytesAvailable); bool asyncOp; try { asyncOp = socket.ReceiveAsync(args); } catch { ((ServiceProtocolIncomingConnection)args.UserToken).Dispose(); args.Dispose(); return; } if (!asyncOp) { Receive(socket, args); } }
private void Send() { currentRequestsCount = 0; packStream.Position = 0; if (isNeedMoreCurrentRequestIdsSize) { isNeedMoreCurrentRequestIdsSize = false; currentRequestIds = new uint[currentRequestIds.Length * 2]; } while (currentRequestsCount < currentRequestIds.Length) { var lastPos = (int)packStream.Position; var request = GetNextRequest(currentRequestsCount == 0); if (request == null) { goto ContinueSending; } packStream.Position += ServiceProtocolRequest.HeaderSize; var startPos = (int)packStream.Position; if (!dataContract.requestPackers.TryGetValue(request.GetType(), out var packerInfo)) { logger.Fatal($"Service protocol client {id}: Could not find request packer by type {request.GetType()}!"); ProcessRequestError(request.id, ServiceProtocolResponseCode.InternalError, RequestStateBeforeSend); packStream.Position = lastPos; request.id = ServiceProtocolDataContract.RequestIdWithoutResponse; goto AfterRequestPackError; } try { packerInfo.packer(packWriter, request); } catch (Exception e) { logger.Fatal($"Service protocol client {id}: Could not pack request! Type: {request.GetType()} Details: {e}"); ProcessRequestError(request.id, ServiceProtocolResponseCode.InternalError, RequestStateBeforeSend); packStream.Position = lastPos; request.id = ServiceProtocolDataContract.RequestIdWithoutResponse; goto AfterRequestPackError; } var endPos = (int)packStream.Position; var requestSize = endPos - startPos; if (requestSize > ServiceProtocolRequest.MaxSize) { logger.Fatal( $"Service protocol client {id}: Could not send request! Request length exceeds allowed size! Type: {request.GetType()} Size: {requestSize} Max size: {ServiceProtocolRequest.MaxSize}"); ProcessRequestError(request.id, ServiceProtocolResponseCode.InternalError, RequestStateBeforeSend); packStream.Position = lastPos; request.id = ServiceProtocolDataContract.RequestIdWithoutResponse; goto AfterRequestPackError; } ServiceProtocolRequest.WriteHeader(sendArgs.Buffer, lastPos, request.id, packerInfo.kind, (ushort)requestSize); AfterRequestPackError: currentRequestIds[currentRequestsCount++] = request.id; if (packStream.Position >= sendBufferSize) { goto ContinueSending; } } isNeedMoreCurrentRequestIdsSize = true; ContinueSending: Thread.MemoryBarrier(); sendArgs.SetBuffer(0, (int)packStream.Position); bool asyncOp; try { var s = socket; if (s == null || !s.Connected) { ContinueSendingAfterFailed(); return; } asyncOp = s.SendAsync(sendArgs); } catch (Exception e) when(e is ObjectDisposedException || e is SocketException || e is NullReferenceException || e is NotSupportedException) { ContinueSendingAfterFailed(); return; } if (!asyncOp) { SendingComplete(null, sendArgs); } }