/// <summary>
        /// Reads and decodes message from the stream from LOC server.
        /// </summary>
        /// <param name="CancellationToken">Cancallation token for async calls.</param>
        /// <param name="CheckProtocolViolation">If set to true, the function checks whether a protocol violation occurred and if so, it sends protocol violation error to the peer.</param>
        /// <returns>Received message of null if the function fails.</returns>
        public async Task <LocProtocolMessage> ReceiveMessageAsync(CancellationToken CancellationToken, bool CheckProtocolViolation = false)
        {
            log.Trace("()");

            LocProtocolMessage res = null;

            RawMessageResult rawMessage = await messageReader.ReceiveMessageAsync(CancellationToken);

            if (rawMessage.Data != null)
            {
                res = (LocProtocolMessage)LocMessageBuilder.CreateMessageFromRawData(rawMessage.Data);
            }
            else
            {
                log.Debug("Connection to LOC server has been terminated.");
            }

            if (CheckProtocolViolation)
            {
                if ((res == null) || rawMessage.ProtocolViolation)
                {
                    await messageProcessor.SendProtocolViolation(this);
                }
            }

            log.Trace("(-):{0}", res != null ? "LocProtocolMessage" : "null");
            return(res);
        }
        /// <summary>
        /// Sends ERROR_PROTOCOL_VIOLATION to client with message ID set to 0x0BADC0DE.
        /// </summary>
        /// <param name="Client">Client to send the error to.</param>
        public async Task SendProtocolViolation(ClientBase Client)
        {
            LocMessageBuilder mb = new LocMessageBuilder(0, new List <SemVer> {
                SemVer.V100
            });
            LocProtocolMessage response = mb.CreateErrorProtocolViolationResponse(new LocProtocolMessage(new Message()
            {
                Id = 0x0BADC0DE
            }));

            await Client.SendMessageAsync(response);
        }
        /// <summary>
        /// Initialize the object.
        /// </summary>
        /// <param name="ServerEndPoint">LOC server address and port.</param>
        public LocClient(IPEndPoint ServerEndPoint, IMessageProcessor MessageProcessor, ComponentShutdown ShutdownSignaling) :
            base(ServerEndPoint, false)
        {
            log = new Logger("IopServerCore.Network.LOC.LocClient");
            log.Trace("(ServerEndPoint:'{0}')", ServerEndPoint);

            config = (ConfigBase)Base.ComponentDictionary[ConfigBase.ComponentName];

            messageBuilder = new LocMessageBuilder(0, new List <SemVer> {
                SemVer.V100
            });
            messageProcessor  = MessageProcessor;
            shutdownSignaling = ShutdownSignaling;

            log.Trace("(-)");
        }
        /// <summary>
        /// Reads messages from the client stream and processes them in a loop until the client disconnects
        /// or until an action (such as a protocol violation) that leads to disconnecting of the client occurs.
        /// </summary>
        /// <param name="Client">TCP client.</param>
        /// <param name="MessageBuilder">Client's message builder.</param>
        public async Task ReceiveMessageLoop(TcpClient Client, LocMessageBuilder MessageBuilder)
        {
            log.Trace("()");

            try
            {
                NetworkStream    stream        = Client.GetStream();
                RawMessageReader messageReader = new RawMessageReader(stream);
                while (!isShutdown)
                {
                    RawMessageResult rawMessage = await messageReader.ReceiveMessageAsync(shutdownCancellationTokenSource.Token);

                    bool disconnect        = rawMessage.Data == null;
                    bool protocolViolation = rawMessage.ProtocolViolation;
                    if (rawMessage.Data != null)
                    {
                        LocProtocolMessage message = (LocProtocolMessage)LocMessageBuilder.CreateMessageFromRawData(rawMessage.Data);
                        if (message != null)
                        {
                            disconnect = !await ProcessMessageAsync(Client, MessageBuilder, message);
                        }
                        else
                        {
                            protocolViolation = true;
                        }
                    }

                    if (protocolViolation)
                    {
                        await SendProtocolViolation(Client);

                        break;
                    }

                    if (disconnect)
                    {
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                log.Error("Exception occurred: {0}", e.ToString());
            }

            log.Trace("(-)");
        }
        /// <summary>
        /// Sends a message to the client over the open network stream.
        /// </summary>
        /// <param name="Client">TCP client.</param>
        /// <param name="Message">Message to send.</param>
        /// <returns>true if the message was sent successfully to the target recipient.</returns>
        private async Task <bool> SendMessageInternalAsync(TcpClient Client, LocProtocolMessage Message)
        {
            log.Trace("()");

            bool res = false;

            string msgStr = Message.ToString();

            log.Trace("Sending message:\n{0}", msgStr);
            byte[] responseBytes = LocMessageBuilder.MessageToByteArray(Message);

            await StreamWriteLock.WaitAsync();

            try
            {
                NetworkStream stream = Client.GetStream();
                if (stream != null)
                {
                    await stream.WriteAsync(responseBytes, 0, responseBytes.Length);

                    res = true;
                }
                else
                {
                    log.Info("Connection to the client has been terminated.");
                }
            }
            catch (IOException)
            {
                log.Info("Connection to the client has been terminated.");
            }
            finally
            {
                StreamWriteLock.Release();
            }

            log.Trace("(-):{0}", res);
            return(res);
        }
        /// <summary>
        /// Handler for each client that connects to the TCP server.
        /// </summary>
        /// <param name="Client">Client that is connected to TCP server.</param>
        private async void ClientHandlerAsync(TcpClient Client)
        {
            LogDiagnosticContext.Start();

            log.Debug("(Client.Client.RemoteEndPoint:{0})", Client.Client.RemoteEndPoint);

            connectedProfileServer = Client;
            connectedProfileServerMessageBuilder = new LocMessageBuilder(0, new List <SemVer>()
            {
                SemVer.V100
            });

            await ReceiveMessageLoop(Client, connectedProfileServerMessageBuilder);

            connectedProfileServerWantsUpdates = false;
            connectedProfileServer             = null;
            Client.Dispose();

            log.Debug("(-)");

            LogDiagnosticContext.Stop();
        }
 /// <summary>
 /// Converts an IoP Network protocol message to a binary format.
 /// </summary>
 /// <param name="Message">IoP Network protocol message.</param>
 /// <returns>Binary representation of the message to be sent over the network.</returns>
 public override byte[] MessageToByteArray(IProtocolMessage Message)
 {
     return(LocMessageBuilder.MessageToByteArray(Message));
 }
 /// <summary>
 /// Constructs ProtoBuf message from raw data read from the network stream.
 /// </summary>
 /// <param name="Data">Raw data to be decoded to the message.</param>
 /// <returns>ProtoBuf message or null if the data do not represent a valid message.</returns>
 public override IProtocolMessage CreateMessageFromRawData(byte[] Data)
 {
     return((IProtocolMessage)LocMessageBuilder.CreateMessageFromRawData(Data));
 }
        /// <summary>
        /// Processes DeregisterServiceRequest message from client.
        /// <para>Removes information about the profile server's NodeProfile.</para>
        /// </summary>
        /// <param name="Client">TCP client that sent the request.</param>
        /// <param name="MessageBuilder">Client's message builder.</param>
        /// <param name="RequestMessage">Full request message.</param>
        /// <returns>Response message to be sent to the client.</returns>
        public LocProtocolMessage ProcessMessageDeregisterServiceRequest(TcpClient Client, LocMessageBuilder MessageBuilder, LocProtocolMessage RequestMessage)
        {
            log.Trace("()");

            LocProtocolMessage res = MessageBuilder.CreateDeregisterServiceResponse(RequestMessage);

            DeregisterServiceRequest deregisterServiceRequest = RequestMessage.Request.LocalService.DeregisterService;

            profileServer.Uninitialize();

            log.Trace("(-):*.Response.Status={0}", res.Response.Status);
            return(res);
        }
        /// <summary>
        /// Processes RegisterServiceRequest message from client.
        /// <para>Obtains information about the profile server's NodeProfile.</para>
        /// </summary>
        /// <param name="Client">TCP client that sent the request.</param>
        /// <param name="MessageBuilder">Client's message builder.</param>
        /// <param name="RequestMessage">Full request message.</param>
        /// <returns>Response message to be sent to the client.</returns>
        public LocProtocolMessage ProcessMessageRegisterServiceRequest(TcpClient Client, LocMessageBuilder MessageBuilder, LocProtocolMessage RequestMessage)
        {
            log.Trace("()");

            LocProtocolMessage res = MessageBuilder.CreateRegisterServiceResponse(RequestMessage);

            RegisterServiceRequest registerServiceRequest = RequestMessage.Request.LocalService.RegisterService;

            byte[] serverId = registerServiceRequest.Service.ServiceData.ToByteArray();
            if ((registerServiceRequest.Service.Type == ServiceType.Profile) && (serverId.Length == 32))
            {
                profileServer.SetNetworkId(serverId);
            }
            else
            {
                log.Error("Received register service request is invalid.");
            }

            log.Trace("(-):*.Response.Status={0}", res.Response.Status);
            return(res);
        }
        /// <summary>
        /// Processes GetNeighbourNodesByDistanceLocalRequest message from client.
        /// <para>Obtains information about the profile server's neighborhood and initiates sending updates to it.</para>
        /// </summary>
        /// <param name="Client">TCP client that sent the request.</param>
        /// <param name="MessageBuilder">Client's message builder.</param>
        /// <param name="RequestMessage">Full request message.</param>
        /// <param name="KeepAlive">This is set to true if KeepAliveAndSendUpdates in the request was set.</param>
        /// <returns>Response message to be sent to the client.</returns>
        public LocProtocolMessage ProcessMessageGetNeighbourNodesByDistanceLocalRequest(TcpClient Client, LocMessageBuilder MessageBuilder, LocProtocolMessage RequestMessage, out bool KeepAlive)
        {
            log.Trace("()");

            LocProtocolMessage res = null;

            GetNeighbourNodesByDistanceLocalRequest getNeighbourNodesByDistanceLocalRequest = RequestMessage.Request.LocalService.GetNeighbourNodes;

            KeepAlive = getNeighbourNodesByDistanceLocalRequest.KeepAliveAndSendUpdates;

            List <NodeInfo> neighborList = new List <NodeInfo>();

            lock (neighborsLock)
            {
                foreach (ProfileServer ps in neighbors.Values)
                {
                    NodeInfo ni = ps.GetNodeInfo();
                    neighborList.Add(ni);
                }
            }

            res = MessageBuilder.CreateGetNeighbourNodesByDistanceLocalResponse(RequestMessage, neighborList);

            log.Trace("(-):*.Response.Status={0}", res.Response.Status);
            return(res);
        }
        /// <summary>
        /// Processing of a message received from a client.
        /// </summary>
        /// <param name="Client">TCP client.</param>
        /// <param name="MessageBuilder">Client's message builder.</param>
        /// <param name="IncomingMessage">Full ProtoBuf message to be processed.</param>
        /// <returns>true if the conversation with the client should continue, false if a protocol violation error occurred and the client should be disconnected.</returns>
        public async Task <bool> ProcessMessageAsync(TcpClient Client, LocMessageBuilder MessageBuilder, LocProtocolMessage IncomingMessage)
        {
            bool res = false;

            log.Debug("()");
            try
            {
                log.Trace("Received message type is {0}, message ID is {1}.", IncomingMessage.MessageTypeCase, IncomingMessage.Id);
                switch (IncomingMessage.MessageTypeCase)
                {
                case Message.MessageTypeOneofCase.Request:
                {
                    LocProtocolMessage responseMessage = MessageBuilder.CreateErrorProtocolViolationResponse(IncomingMessage);
                    Request            request         = IncomingMessage.Request;

                    bool setKeepAlive = false;

                    SemVer version = new SemVer(request.Version);
                    log.Trace("Request type is {0}, version is {1}.", request.RequestTypeCase, version);
                    switch (request.RequestTypeCase)
                    {
                    case Request.RequestTypeOneofCase.LocalService:
                    {
                        log.Trace("Local service request type is {0}.", request.LocalService.LocalServiceRequestTypeCase);
                        switch (request.LocalService.LocalServiceRequestTypeCase)
                        {
                        case LocalServiceRequest.LocalServiceRequestTypeOneofCase.RegisterService:
                            responseMessage = ProcessMessageRegisterServiceRequest(Client, MessageBuilder, IncomingMessage);
                            break;

                        case LocalServiceRequest.LocalServiceRequestTypeOneofCase.DeregisterService:
                            responseMessage = ProcessMessageDeregisterServiceRequest(Client, MessageBuilder, IncomingMessage);
                            break;

                        case LocalServiceRequest.LocalServiceRequestTypeOneofCase.GetNeighbourNodes:
                            responseMessage = ProcessMessageGetNeighbourNodesByDistanceLocalRequest(Client, MessageBuilder, IncomingMessage, out setKeepAlive);
                            break;

                        default:
                            log.Error("Invalid local service request type '{0}'.", request.LocalService.LocalServiceRequestTypeCase);
                            break;
                        }
                        break;
                    }

                    default:
                        log.Error("Invalid request type '{0}'.", request.RequestTypeCase);
                        break;
                    }


                    if (responseMessage != null)
                    {
                        // Send response to client.
                        res = await SendMessageAsync(Client, responseMessage);

                        if (res)
                        {
                            // If the message was sent successfully to the target, we close the connection only in case of protocol violation error.
                            if (responseMessage.MessageTypeCase == Message.MessageTypeOneofCase.Response)
                            {
                                res = responseMessage.Response.Status != Status.ErrorProtocolViolation;
                            }
                        }

                        if (res && setKeepAlive)
                        {
                            connectedProfileServerWantsUpdates = true;
                            log.Debug("Profile server '{0}' is now connected to its LOC server and waiting for updates.", profileServer.Name);
                        }
                    }
                    else
                    {
                        // If there is no response to send immediately to the client,
                        // we want to keep the connection open.
                        res = true;
                    }
                    break;
                }

                case Message.MessageTypeOneofCase.Response:
                {
                    Response response = IncomingMessage.Response;
                    log.Trace("Response status is {0}, details are '{1}', response type is {2}.", response.Status, response.Details, response.ResponseTypeCase);

                    switch (response.ResponseTypeCase)
                    {
                    case Response.ResponseTypeOneofCase.LocalService:
                    {
                        log.Trace("Local service response type is {0}.", response.LocalService.LocalServiceResponseTypeCase);
                        switch (response.LocalService.LocalServiceResponseTypeCase)
                        {
                        case LocalServiceResponse.LocalServiceResponseTypeOneofCase.NeighbourhoodUpdated:
                            // Nothing to be done here.
                            res = true;
                            break;

                        default:
                            log.Error("Invalid local service response type '{0}'.", response.LocalService.LocalServiceResponseTypeCase);
                            break;
                        }

                        break;
                    }

                    default:
                        log.Error("Unknown response type '{0}'.", response.ResponseTypeCase);
                        // Connection will be closed in ReceiveMessageLoop.
                        break;
                    }

                    break;
                }

                default:
                    log.Error("Unknown message type '{0}', connection to the client will be closed.", IncomingMessage.MessageTypeCase);
                    await SendProtocolViolation(Client);

                    // Connection will be closed in ReceiveMessageLoop.
                    break;
                }
            }
            catch (Exception e)
            {
                log.Error("Exception occurred, connection to the client will be closed: {0}", e.ToString());
                await SendProtocolViolation(Client);

                // Connection will be closed in ReceiveMessageLoop.
            }

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