Example #1
0
        /// <summary>
        /// Sends a request message to the client over the open network stream and stores the request to the list of unfinished requests.
        /// </summary>
        /// <param name="Message">Message to send.</param>
        /// <param name="Context">Caller's defined context to store information required for later response processing.</param>
        /// <returns>true if the connection to the client should remain open, false otherwise.</returns>
        public async Task <bool> SendMessageAndSaveUnfinishedRequestAsync(Message Message, object Context)
        {
            log.Trace("()");
            bool res = false;

            UnfinishedRequest unfinishedRequest = new UnfinishedRequest(Message, Context);

            if (AddUnfinishedRequest(unfinishedRequest))
            {
                res = await SendMessageInternalAsync(Message);

                if (res)
                {
                    // If the message was sent successfully to the target, we close the connection only in case it was a protocol violation error response.
                    if (Message.MessageTypeCase == Message.MessageTypeOneofCase.Response)
                    {
                        res = Message.Response.Status != Status.ErrorProtocolViolation;
                    }
                }
                else
                {
                    RemoveUnfinishedRequest(unfinishedRequest.RequestMessage.Id);
                }
            }

            log.Trace("(-):{0}", res);
            return(res);
        }
Example #2
0
        /// <summary>
        /// Finds an unfinished request message by its ID and removes it from the list.
        /// </summary>
        /// <param name="Id">Identifier of the message to find.</param>
        /// <returns>Unfinished request with the given ID, or null if no such request is in the list.</returns>
        public UnfinishedRequest GetAndRemoveUnfinishedRequest(uint Id)
        {
            log.Trace("(Id:{0})", Id);

            UnfinishedRequest res = null;

            lock (unfinishedRequestsLock)
            {
                if (unfinishedRequests.TryGetValue(Id, out res))
                {
                    unfinishedRequests.Remove(Id);
                }
            }

            log.Trace("(-):{0},unfinishedRequests.Count={1}", res != null ? "UnfinishedRequest" : "null", unfinishedRequests.Count);
            return(res);
        }
Example #3
0
        /// <summary>
        /// Adds unfinished request to the list of unfinished requests.
        /// </summary>
        /// <param name="Request">Request to add to the list.</param>
        /// <returns>true if the function succeeds, false if the number of unfinished requests is over the limit.</returns>
        public bool AddUnfinishedRequest(UnfinishedRequest Request)
        {
            log.Trace("(Request.RequestMessage.Id:{0})", Request.RequestMessage.Id);

            bool res = false;

            lock (unfinishedRequestsLock)
            {
                if (unfinishedRequests.Count < MaxUnfinishedRequests)
                {
                    unfinishedRequests.Add(Request.RequestMessage.Id, Request);
                    res = true;
                }
            }

            log.Trace("(-):{0},unfinishedRequests.Count={1}", res, unfinishedRequests.Count);
            return(res);
        }
        /// <summary>
        /// Handles situation when the callee replied to the incoming call notification request.
        /// </summary>
        /// <param name="ResponseMessage">Full response message from the callee.</param>
        /// <param name="Request">Unfinished call request message of the caller that corresponds to the response message.</param>
        /// <returns></returns>
        public async Task <bool> CalleeRepliedToIncomingCallNotification(Message ResponseMessage, UnfinishedRequest Request)
        {
            log.Trace("()");

            bool res = false;

            bool    destroyRelay        = false;
            Client  clientToSendMessage = null;
            Message messageToSend       = null;

            await lockObject.WaitAsync();


            if (status == RelayConnectionStatus.WaitingForCalleeResponse)
            {
                CancelTimeoutTimerLocked();

                // The caller is still connected and waiting for an answer to its call request.
                if (ResponseMessage.Response.Status == Status.Ok)
                {
                    // The callee is now expected to connect to clAppService with its token.
                    // We need to inform caller that the callee accepted the call.
                    // This is option 4) from ProcessMessageCallIdentityApplicationServiceRequestAsync.
                    messageToSend       = caller.MessageBuilder.CreateCallIdentityApplicationServiceResponse(pendingMessage, callerToken.ToByteArray());
                    clientToSendMessage = caller;
                    pendingMessage      = null;

                    caller = null;
                    callee = null;
                    status = RelayConnectionStatus.WaitingForFirstInitMessage;
                    log.Debug("Relay '{0}' status has been changed to {1}.", id, status);

                    /// Install timeoutTimer to expire if the first client does not connect to clAppService port
                    /// and send its initialization message within reasonable time.
                    timeoutTimer = new Timer(TimeoutCallback, RelayConnectionStatus.WaitingForFirstInitMessage, FirstAppServiceInitializationMessageDelayMaxSeconds * 1000, Timeout.Infinite);

                    res = true;
                }
                else
                {
                    // The callee rejected the call or reported other error.
                    // These are options 3) and 2) from ProcessMessageCallIdentityApplicationServiceRequestAsync.
                    if (ResponseMessage.Response.Status == Status.ErrorRejected)
                    {
                        log.Debug("Callee ID '0x{0:X16}' rejected the call from caller identity ID '0x{1:X16}', relay '{2}'.", callee.Id, caller.Id, id);
                        messageToSend = caller.MessageBuilder.CreateErrorRejectedResponse(pendingMessage);
                    }
                    else
                    {
                        log.Warn("Callee ID '0x{0:X16}' sent error response '{1}' for call request from caller identity ID '0x{2:X16}', relay '{3}'.",
                                 callee.Id, ResponseMessage.Response.Status, caller.Id, id);

                        messageToSend = caller.MessageBuilder.CreateErrorNotAvailableResponse(pendingMessage);
                    }

                    clientToSendMessage = caller;
                    destroyRelay        = true;
                }
            }
            else
            {
                // The relay has probably been destroyed, or something bad happened to it.
                // We take no action here regardless of what the callee's response is.
                // If it rejected the call, there is nothing to be done since we do not have
                // any connection to the caller anymore.
                log.Debug("Relay status is {0}, nothing to be done.", status);
            }

            lockObject.Release();


            if (messageToSend != null)
            {
                if (await clientToSendMessage.SendMessageAsync(messageToSend))
                {
                    log.Debug("Response to call initiation request sent to the caller ID '0x{0:X16}'.", clientToSendMessage.Id);
                }
                else
                {
                    log.Debug("Unable to reponse to call initiation request to the caller ID '0x{0:X16}'.", clientToSendMessage.Id);
                }
            }

            if (destroyRelay)
            {
                Server     serverComponent = (Server)Base.ComponentDictionary["Network.Server"];
                ClientList clientList      = serverComponent.GetClientList();
                await clientList.DestroyNetworkRelay(this);
            }

            log.Trace("(-):{0}", res);
            return(res);
        }