예제 #1
0
        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);
        }
예제 #2
0
        private void AddToSendQueue(ServiceProtocolRequest request)
        {
            var newValue = Interlocked.Increment(ref requestsQueueSize);

            Thread.MemoryBarrier();

            requestsQueue.Enqueue(request);

            if (newValue == 1)
            {
                Task.Run(() => Send());
            }
        }
예제 #3
0
        public void SendRequestWithoutResponse(ServiceProtocolRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            request.id = ServiceProtocolDataContract.RequestIdWithoutResponse;

            Thread.MemoryBarrier();

            AddToSendQueue(request);
        }
예제 #4
0
        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);
            }
        }
예제 #5
0
        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);
            }
        }