/// <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(TcpClient Client) { MessageBuilderLocNet mb = new MessageBuilderLocNet(0, new List <SemVer>() { SemVer.V100 }); Message response = mb.CreateErrorProtocolViolationResponse(new Message() { Id = 0x0BADC0DE }); await SendMessageAsync(Client, response); }
/// <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 Message ProcessMessageDeregisterServiceRequest(TcpClient Client, MessageBuilderLocNet MessageBuilder, Message RequestMessage) { log.Trace("()"); Message res = MessageBuilder.CreateDeregisterServiceResponse(RequestMessage); DeregisterServiceRequest deregisterServiceRequest = RequestMessage.Request.LocalService.DeregisterService; profileServerPort = 0; log.Trace("(-):*.Response.Status={0}", res.Response.Status); return(res); }
/// <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, MessageBuilderLocNet 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) { Message message = 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> /// 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) { log.Debug("(Client.Client.RemoteEndPoint:{0})", Client.Client.RemoteEndPoint); connectedProfileServer = Client; connectedProfileServerMessageBuilder = new MessageBuilderLocNet(0, new List <SemVer>() { SemVer.V100 }); await ReceiveMessageLoop(Client, connectedProfileServerMessageBuilder); connectedProfileServerWantsUpdates = false; connectedProfileServer = null; Client.Dispose(); log.Debug("(-)"); }
/// <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 Message ProcessMessageRegisterServiceRequest(TcpClient Client, MessageBuilderLocNet MessageBuilder, Message RequestMessage) { log.Trace("()"); Message 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 Message ProcessMessageGetNeighbourNodesByDistanceLocalRequest(TcpClient Client, MessageBuilderLocNet MessageBuilder, Message RequestMessage, out bool KeepAlive) { log.Trace("()"); Message res = null; GetNeighbourNodesByDistanceLocalRequest getNeighbourNodesByDistanceLocalRequest = RequestMessage.Request.LocalService.GetNeighbourNodes; KeepAlive = getNeighbourNodesByDistanceLocalRequest.KeepAliveAndSendUpdates; List <NodeInfo> neighborList; lock (neighborsLock) { neighborList = new List <NodeInfo>(neighbors); } 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, MessageBuilderLocNet MessageBuilder, Message 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: { Message 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 (setKeepAlive) { connectedProfileServerWantsUpdates = true; log.Debug("Profile server is now connected to its LOC server and waiting for updates."); } } 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); }