// Receive incoming initial Connection messages from Clients... public static void AddToConnectionList(PacketHeader header, Connection connection, string Connection) { // Add incoming IP Address to HashSet list... ConnectionsList.Add(connection.ConnectionInfo.RemoteEndPoint.Address.ToString() + "|" + Connection); // Respond to sender that they are succesfully connected. connection.SendObject("Connected", "CONNECTED!"); Console.WriteLine("\n" + connection.ConnectionInfo.RemoteEndPoint.Address.ToString() + " has CONNECTED!"); // Send all active connections to all active connections for Client List. foreach (var item in NetworkComms.GetExistingConnection()) { foreach (var items in ConnectionsList.Distinct()) { item.SendObject("Connection", items); } } /* Old method to create files on hard disk for testing the code... if (!File.Exists(ConnectionFilePath)) { // Create a file to write to. using (StreamWriter sw = File.CreateText(ConnectionFilePath)) { } } using (StreamWriter sw = File.AppendText(ConnectionFilePath)) { sw.WriteLine(connection.ConnectionInfo.RemoteEndPoint.Address.ToString()); } */ }
private static void IncomingMessage(PacketHeader header, Connection connection, string message) { // Parse studio number int studioNumber = ParseStudioNumber(message); // Execute action for each command if (message == "EMERGENCY") // If emergency output has come on { if (EmergencyOn != null) { EmergencyOn(null, new EventArgs()); } } else if (message.StartsWith("STUDIO")) { if (StudioOnAir != null) { StudioOnAir(null, new StudioEventArgs(studioNumber)); } } else if (message.StartsWith("MIC LIVE")) { if (MicLive != null) { MicLive(null, new StudioEventArgs(studioNumber)); } } else if (message.StartsWith("MIC OFF")) { if (MicOff != null) { MicOff(null, new StudioEventArgs(studioNumber)); } } }
private static void AddToConnectionList_Server(PacketHeader header, Connection connection, string Connection) { // Add incoming IP Address to HashSet list... ConnectionsList_Server.Add(connection.ConnectionInfo.RemoteEndPoint.Address.ToString() + "|" + Connection); // Respond to sender that they are succesfully connected. connection.SendObject("Connected", "CONNECTED!"); //richTextBox1.AppendText("\n" + connection.ConnectionInfo.RemoteEndPoint.Address.ToString() + " has CONNECTED!" + Environment.NewLine); // Send all active connections to all active connections for Client List. foreach (var item in NetworkComms.GetExistingConnection()) { foreach (var items in ConnectionsList_Server.Distinct()) { item.SendObject("Connection", items); } } }
private void PluginMessageReceived(PacketHeader header, Connection connection, string message) { logging.AddToLog("\nA message was recieved from " + connection.ToString() + " which said '" + message + "'.", true); string[] arguments = message.Split('|'); bool local = false; if (arguments[1] == "True") { OSAEObjectStateManager.ObjectStateSet(arguments[0], "ON", sourceName); } else if (arguments[1] == "False") { OSAEObjectStateManager.ObjectStateSet(arguments[0], "OFF", sourceName); } foreach (Plugin p in plugins) { if (p.PluginName == arguments[0]) { local = true; OSAEObject obj = OSAEObjectManager.GetObjectByName(p.PluginName); if (obj != null) { if (arguments[1] == "True") { enablePlugin(p); UDPConnection.SendObject("Plugin", p.PluginName + " | " + p.Enabled.ToString() + " | " + p.PluginVersion + " | Running | " + p.LatestAvailableVersion + " | " + p.PluginType + " | " + Common.ComputerName, new IPEndPoint(IPAddress.Broadcast, 10000)); } else if (arguments[1] == "False") { disablePlugin(p); UDPConnection.SendObject("Plugin", p.PluginName + " | " + p.Enabled.ToString() + " | " + p.PluginVersion + " | Stopped | " + p.LatestAvailableVersion + " | " + p.PluginType + " | " + Common.ComputerName, new IPEndPoint(IPAddress.Broadcast, 10000)); } } } } if (!local) { UDPConnection.SendObject("Plugin", message, new IPEndPoint(IPAddress.Broadcast, 10000)); } }
private void PluginMessageReceived(PacketHeader header, Connection connection, string message) { Log.Info("A message was recieved from " + connection.ToString() + " which said '" + message + "'."); string[] arguments = message.Split('|'); bool local = false; if (arguments[1] == "True") OSAEObjectStateManager.ObjectStateSet(arguments[0], "ON", "SYSTEM"); else if (arguments[1] == "False") OSAEObjectStateManager.ObjectStateSet(arguments[0], "OFF", "SYSTEM"); foreach (Plugin p in plugins) { if (p.PluginName == arguments[0]) { local = true; OSAEObject obj = OSAEObjectManager.GetObjectByName(p.PluginName); if (obj != null) { if (arguments[1] == "True") { // enablePlugin(p); // maybe this call should be enable/disable, not sure, moving on startPlugin("SYSTEM", p); UDPConnection.SendObject("Plugin", p.PluginName + " | " + p.Enabled.ToString() + " | " + p.PluginVersion + " | Running | " + p.LatestAvailableVersion + " | " + p.PluginType + " | " + Common.ComputerName, new IPEndPoint(IPAddress.Broadcast, 10051)); } else if (arguments[1] == "False") { stopPlugin("SYSTEM", p); UDPConnection.SendObject("Plugin", p.PluginName + " | " + p.Enabled.ToString() + " | " + p.PluginVersion + " | Stopped | " + p.LatestAvailableVersion + " | " + p.PluginType + " | " + Common.ComputerName, new IPEndPoint(IPAddress.Broadcast, 10051)); } } } } if (!local) UDPConnection.SendObject("Plugin", message, new IPEndPoint(IPAddress.Broadcast, 10051)); }
private void PluginMessageReceived(PacketHeader header, Connection connection, string message) { string[] split = message.Split('|'); bool enabled = false; if (split[1].Trim() == "True") { enabled = true; } foreach (PluginDescription plugin in pluginList) { if ((plugin.Type == split[5].Trim() && Common.ComputerName == split[6].Trim()) || plugin.Name == split[0].Trim()) { if (split[3].Trim() == "ON") plugin.Status = "Running"; else if (split[3].Trim() == "OFF") plugin.Status = "Stopped"; else plugin.Status = split[3].Trim(); plugin.Enabled = enabled; plugin.Name = split[0].Trim(); if (split[4].Trim() != "") plugin.Upgrade = split[4].Trim(); else { plugin.Upgrade = string.Empty; } this.Log.Info("updated plugin: " + plugin.Name + "|" + plugin.Version + "|" + plugin.Upgrade + "|" + plugin.Status + "| " + plugin.Enabled.ToString()); break; } } }
/// <summary> /// Performs whatever functions we might so desire when we receive an incoming ChatMessage /// </summary> /// <param name="header">The PacketHeader corresponding with the received object</param> /// <param name="connection">The Connection from which this object was received</param> /// <param name="incomingMessage">The incoming ChatMessage we are after</param> protected virtual void HandleIncomingChatMessage(PacketHeader header, Connection connection, ChatMessage incomingMessage) { //We only want to write a message once to the chat window //Because we support relaying and may receive the same message twice from multiple sources //we use our history and message indexes to ensure we have a new message //We perform this action within a lock as HandleIncomingChatMessage could be called in parallel lock (lastPeerMessageDict) { if (lastPeerMessageDict.ContainsKey(incomingMessage.SourceIdentifier)) { if (lastPeerMessageDict[incomingMessage.SourceIdentifier].MessageIndex < incomingMessage.MessageIndex) { //If this message index is greater than the last seen from this source we can safely //write the message to the ChatBox AppendLineToChatHistory(incomingMessage.SourceName + " - " + incomingMessage.Message); //We now replace the last received message with the current one lastPeerMessageDict[incomingMessage.SourceIdentifier] = incomingMessage; } } else { //If we have never had a message from this source before then it has to be new //by definition lastPeerMessageDict.Add(incomingMessage.SourceIdentifier, incomingMessage); AppendLineToChatHistory(incomingMessage.SourceName + " - " + incomingMessage.Message); } } //This last section of the method is the relay feature //We start by checking to see if this message has already been relayed the maximum number of times if (incomingMessage.RelayCount < relayMaximum) { //If we are going to relay this message we need an array of //all known connections, excluding the current one var allRelayConnections = (from current in NetworkComms.GetExistingConnection() where current != connection select current).ToArray(); //We increment the relay count before we send incomingMessage.IncrementRelayCount(); //We now send the message to every other connection foreach (var relayConnection in allRelayConnections) { //We ensure we perform the send within a try catch //To ensure a single failed send will not prevent the //relay to all working connections. try { relayConnection.SendObject("ChatMessage", incomingMessage); } catch (CommsException) { /* Catch the general comms exception, ignore and continue */ } } } }
private void MethodMessageReceived(PacketHeader header, Connection connection, string message) { Log.Info("A message was recieved from " + connection.ToString() + " which said '" + message + "'."); }
private void ReceivedMessageTcpBytes(PacketHeader header, ConnectionTcp connection, byte[] message) { HandledTask task = new HandledTask(() => { _Clients[connection].ProcessCompressedMessage(ref message); }); task.Start(); }
/// <summary> /// UDP - Used by a client when requesting a list of known peers /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="itemCheckSum"></param> private static void KnownPeersRequest(PacketHeader packetHeader, Connection connection, string itemCheckSum) { try { DistributedItem selectedItem = null; if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... known peers request for item (" + itemCheckSum + ")."); lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(itemCheckSum)) selectedItem = swarmedItemsDict[itemCheckSum]; } if (selectedItem == null) //Inform peer that we don't actually have the requested item so that it won't bother us again UDPConnection.SendObject("DFS_ItemRemovalUpdate", new ItemRemovalUpdate(NetworkComms.NetworkIdentifier, itemCheckSum, false), (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, nullCompressionSRO); else UDPConnection.SendObject("DFS_KnownPeersUpdate", new KnownPeerEndPoints(selectedItem.Data.CompleteDataCheckSum, selectedItem.SwarmChunkAvailability.AllPeerEndPoints()), (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, nullCompressionSRO); } catch (CommsException) { //LogTools.LogException(e, "CommsError_IncomingChunkAvailabilityRequest"); } catch (Exception e) { LogTools.LogException(e, "Error_KnownPeersRequest"); } }
/// <summary> /// Returns the <see cref="SendReceiveOptions"/> to be used for the provided <see cref="PacketHeader"/>. Ensures there will not be a serializer / data processor clash for different delegate levels. /// </summary> /// <param name="header">The <see cref="PacketHeader"/> options are desired.</param> /// <returns>The requested <see cref="SendReceiveOptions"/></returns> private SendReceiveOptions IncomingPacketSendReceiveOptions(PacketHeader header) { //Are there connection specific or global packet handlers? bool connectionSpecificHandlers = false; lock (delegateLocker) connectionSpecificHandlers = incomingPacketHandlers.ContainsKey(header.PacketType); bool globalHandlers = NetworkComms.GlobalIncomingPacketHandlerExists(header.PacketType); //Get connection specific options for this packet type, if there arn't any use the connection default options SendReceiveOptions connectionSpecificOptions = PacketTypeUnwrapperOptions(header.PacketType); if (connectionSpecificOptions == null) { connectionSpecificOptions = ConnectionDefaultSendReceiveOptions; } //Get global options for this packet type, if there arn't any use the global default options SendReceiveOptions globalOptions = NetworkComms.GlobalPacketTypeUnwrapperOptions(header.PacketType); if (globalOptions == null) { globalOptions = NetworkComms.DefaultSendReceiveOptions; } if (connectionSpecificHandlers && globalHandlers) { if (!connectionSpecificOptions.OptionsCompatible(globalOptions)) { throw new PacketHandlerException("Attempted to determine correct sendReceiveOptions for packet of type '" + header.PacketType + "'. Unable to continue as connection specific and global sendReceiveOptions are not equal."); } //We need to combine options in this case using the connection specific option in preference if both are present var combinedOptions = new Dictionary <string, string>(globalOptions.Options); foreach (var pair in connectionSpecificOptions.Options) { combinedOptions[pair.Key] = pair.Value; } //If the header specifies a serializer and data processors we will autodetect those if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors)) { DataSerializer serializer; List <DataProcessor> dataProcessors; DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors); return(new SendReceiveOptions(serializer, dataProcessors, combinedOptions)); } //Otherwise we will use options that were specified return(new SendReceiveOptions(connectionSpecificOptions.DataSerializer, connectionSpecificOptions.DataProcessors, combinedOptions)); } else if (connectionSpecificHandlers) { //If the header specifies a serializer and data processors we will autodetect those if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors)) { DataSerializer serializer; List <DataProcessor> dataProcessors; DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors); return(new SendReceiveOptions(serializer, dataProcessors, connectionSpecificOptions.Options)); } return(connectionSpecificOptions); } else { //If the header specifies a serializer and data processors we will autodetect those if (header.ContainsOption(PacketHeaderLongItems.SerializerProcessors)) { DataSerializer serializer; List <DataProcessor> dataProcessors; DPSManager.GetSerializerDataProcessorsFromIdentifier(header.GetOption(PacketHeaderLongItems.SerializerProcessors), out serializer, out dataProcessors); return(new SendReceiveOptions(serializer, dataProcessors, globalOptions.Options)); } //If just globalHandlers is set (or indeed no handlers atall we just return the global options return(globalOptions); } }
/// <summary> /// Trigger connection specific packet delegates with the provided parameters. Returns true if connection specific handlers were executed. /// </summary> /// <param name="packetHeader">The packetHeader for which all delegates should be triggered with</param> /// <param name="incomingObjectBytes">The serialised and or compressed bytes to be used</param> /// <param name="options">The incoming sendReceiveOptions to use overriding defaults</param> /// <returns>Returns true if connection specific handlers were executed.</returns> public bool TriggerSpecificPacketHandlers(PacketHeader packetHeader, MemoryStream incomingObjectBytes, SendReceiveOptions options) { try { if (packetHeader == null) { throw new ArgumentNullException("packetHeader", "Provided PacketHeader cannot not be null."); } if (incomingObjectBytes == null) { throw new ArgumentNullException("incomingObjectBytes", "Provided MemoryStream cannot not be null for packetType " + packetHeader.PacketType); } if (options == null) { throw new ArgumentNullException("options", "Provided SendReceiveOptions cannot not be null for packetType " + packetHeader.PacketType); } //We take a copy of the handlers list incase it is modified outside of the lock List <IPacketTypeHandlerDelegateWrapper> handlersCopy = null; lock (delegateLocker) if (incomingPacketHandlers.ContainsKey(packetHeader.PacketType)) { handlersCopy = new List <IPacketTypeHandlerDelegateWrapper>(incomingPacketHandlers[packetHeader.PacketType]); } if (handlersCopy == null) { //If we have received an unknown packet type we ignore them on this connection specific level and just finish here return(false); } else { //Idiot check if (handlersCopy.Count == 0) { throw new PacketHandlerException("An entry exists in the packetHandlers list but it contains no elements. This should not be possible."); } //Deserialise the object only once object returnObject = handlersCopy[0].DeSerialize(incomingObjectBytes, options); //Pass the data onto the handler and move on. if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... passing completed data packet to selected connection specific handlers."); } //Pass the object to all necessary delgates //We need to use a copy because we may modify the original delegate list during processing foreach (IPacketTypeHandlerDelegateWrapper wrapper in handlersCopy) { try { wrapper.Process(packetHeader, this, returnObject); } catch (Exception ex) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Fatal("An unhandled exception was caught while processing a packet handler for a packet type '" + packetHeader.PacketType + "'. Make sure to catch errors in packet handlers. See error log file for more information."); } NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType); } } } } catch (Exception ex) { //If anything goes wrong here all we can really do is log the exception if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Fatal("An exception occured in TriggerPacketHandler() for a packet type '" + packetHeader.PacketType + "'. See error log file for more information."); } NetworkComms.LogError(ex, "PacketHandlerErrorSpecific_" + packetHeader.PacketType); } return(true); }
private static void HandleIncomingMessage(PacketHeader header, Connection connection, iRTVOMessage incomingMessage) { logger.Log(NLog.LogLevel.Debug,"HandleIncomingMessage: {0}", incomingMessage.ToString()); if (isServer && (incomingMessage.Command == "AUTHENTICATE")) { if ((incomingMessage.Arguments == null) || (incomingMessage.Arguments.Count() != 1)) { logger.Error("HandleIncomingMessage: Wrong arguments to Authenticate from {0}", connection.ConnectionInfo.NetworkIdentifier); connection.CloseConnection(false,-100); return; } if (String.Compare(_Password, Convert.ToString(incomingMessage.Arguments[0])) != 0) { logger.Error("HandleIncomingMessage: Worng Password from {0}", connection.ConnectionInfo.NetworkIdentifier); connection.CloseConnection(false,-200); } logger.Info("Client {0} authenticated.", connection.ConnectionInfo.NetworkIdentifier); isAuthenticated[connection.ConnectionInfo.NetworkIdentifier] = true; connection.SendObject("iRTVOMessage", new iRTVOMessage(NetworkComms.NetworkIdentifier, "AUTHENTICATED")); if (_NewClient != null) _NewClient(connection.ConnectionInfo.NetworkIdentifier); return; } if (!isServer && (incomingMessage.Command == "AUTHENTICATED")) { if (_ClientConnectionEstablished != null) _ClientConnectionEstablished(); return; } if (isServer && (!isAuthenticated.ContainsKey(connection.ConnectionInfo.NetworkIdentifier) || !isAuthenticated[connection.ConnectionInfo.NetworkIdentifier])) { logger.Warn("HandleIncomingMessage: Command from unauthorized client {0}",connection.ConnectionInfo.NetworkIdentifier); connection.CloseConnection(false,-300); return; } iRTVORemoteEvent e = new iRTVORemoteEvent(incomingMessage); if (_ProcessMessage != null) { using ( TimeCall tc = new TimeCall("ProcessMessage") ) _ProcessMessage(e); } // Handler signals to abort this connection! if (e.Cancel) { logger.Error("HandleIncomingMessage: ProcessMessage signaled to close client {0}", connection.ConnectionInfo.NetworkIdentifier); connection.CloseConnection(true, -400); } else { if (isServer && e.Forward) ForwardMessage(incomingMessage); } }
/// <summary> /// Deserializes from a memory stream to a <see cref="PacketHeader"/> object /// </summary> /// <param name="inputStream">The memory stream containing the serialized <see cref="PacketHeader"/></param> /// <param name="result">The deserialized <see cref="PacketHeader"/></param> public static void Deserialize(Stream inputStream, out PacketHeader result) { result = new PacketHeader(); result.Deserialize(inputStream); }
private void PluginMessageReceived(PacketHeader header, Connection connection, string message) { string[] arguments = message.Split('|'); if (arguments[1] == "True") OSAEObjectStateManager.ObjectStateSet(arguments[0], "ON", sourceName); else if (arguments[1] == "False") OSAEObjectStateManager.ObjectStateSet(arguments[0], "OFF", sourceName); foreach (Plugin p in plugins) { if (p.PluginName == arguments[0]) { OSAEObject obj = OSAEObjectManager.GetObjectByName(p.PluginName); if (obj != null) { bool isSystemPlugin = false; foreach (OSAEObjectProperty p2 in obj.Properties) { if (p2.Name == "System Plugin") { if (p2.Value == "TRUE") isSystemPlugin = true; break; } } if (arguments[1] == "True" && !p.Enabled && !isSystemPlugin) { OSAEObjectManager.ObjectUpdate(p.PluginName, p.PluginName, obj.Description, obj.Type, obj.Address, obj.Container, 1); try { enablePlugin(p); logging.AddToLog("Activated plugin: " + p.PluginName, false); } catch (Exception ex) { logging.AddToLog("Error activating plugin (" + p.PluginName + "): " + ex.Message + " - " + ex.InnerException, true); } } else if (arguments[1] == "False" && p.Enabled && !isSystemPlugin) { OSAEObjectManager.ObjectUpdate(p.PluginName, p.PluginName, obj.Description, obj.Type, obj.Address, obj.Container, 0); try { disablePlugin(p); logging.AddToLog("Deactivated plugin: " + p.PluginName, false); } catch (Exception ex) { logging.AddToLog("Error stopping plugin (" + p.PluginName + "): " + ex.Message + " - " + ex.InnerException, true); } } } } } }
private void MethodMessageReceived(PacketHeader header, Connection connection, string message) { Log.Info("<- Command: " + message); string[] items = message.Split('|'); //ObjectName + " | " + MethodName + " | " + Parameter1 + " | " + Parameter2 + " | " + Address + " | " + Owner + " | " +From, new IPEndPoint(IPAddress.Broadcast, 10051)); OSAEMethod method = new OSAEMethod(items[0].Trim(), items[1].Trim(), "", items[2].Trim(), items[3].Trim(), items[4].Trim(), items[5].Trim(), items[6].Trim()); Log.Info("Created Method object." + method.ObjectName); if (method.ObjectName == "SERVICE-" + Common.ComputerName) { if (method.MethodName == "RESTART PLUGIN") { foreach (Plugin p in plugins) { if (p.PluginName == method.Parameter1) { bool found = OSAEObjectManager.ObjectExists(p.PluginName); if (found) { stopPlugin(p); startPlugin(p); } } } } else if (method.MethodName == "START PLUGIN") { foreach (Plugin p in plugins) { if (p.PluginName == method.Parameter1) { bool found = OSAEObjectManager.ObjectExists(p.PluginName); if (found) startPlugin(p); } } } else if (method.MethodName == "STOP PLUGIN") { foreach (Plugin p in plugins) { if (p.PluginName == method.Parameter1) { bool found = OSAEObjectManager.ObjectExists(p.PluginName); if (found) stopPlugin(p); } } } } else { Log.Info("Passing Method to: " + method.ObjectName); foreach (Plugin plugin in plugins) { //This exposes a flaw in the Ownership of distributed plugins. Log.Info("does " + method.ObjectName + " = " + plugin.PluginName); if (plugin.Running && method.ObjectName == plugin.PluginName) { plugin.ExecuteCommand(method); Log.Info("Passed Method to: " + method.ObjectName); } } } }
private static void PrintIncomingMessage(PacketHeader header, Connection connection, string message) { Console.WriteLine(message); }
/// <summary> /// TCP - A remote peer is trying to link DFS items /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="linkRequestData"></param> private static void IncomingRemoteItemLinkRequest(PacketHeader packetHeader, Connection connection, DFSLinkRequest linkRequestData) { try { var localItemKeys = AllLocalDFSItemsWithBuildTime(); //We only check for potential links if the remote end has provided us with some items to link if (linkRequestData.AvailableItems.Count > 0) { //Get the item matches using linq. Could also use localItemKeys.Intersect<long>(linkRequestData.AvailableItemCheckSums); DistributedItem[] itemsToLink = null; lock (globalDFSLocker) itemsToLink= (from current in localItemKeys.Keys join remote in linkRequestData.AvailableItems.Keys on current equals remote where swarmedItemsDict.ContainsKey(current) select swarmedItemsDict[current]).ToArray(); for (int i = 0; i < itemsToLink.Length; i++) itemsToLink[i].SwarmChunkAvailability.AddOrUpdateCachedPeerChunkFlags(connection.ConnectionInfo, new ChunkFlags(itemsToLink[i].Data.TotalNumChunks), true); } //If this link request is from the original requester then we reply with our own items list if (!linkRequestData.LinkRequestReply) { //If a specific return packet type has been requested we use that if (packetHeader.RequestedReturnPacketType != null) connection.SendObject(packetHeader.RequestedReturnPacketType, new DFSLinkRequest(localItemKeys, true), nullCompressionSRO); else connection.SendObject("DFS_ItemLinkRequest", new DFSLinkRequest(localItemKeys, true), nullCompressionSRO); } } catch (CommsException e) { LogTools.LogException(e, "CommsError_IncomingRemoteItemLinkRequest"); } catch (Exception e) { LogTools.LogException(e, "Error_IncomingRemoteItemLinkRequest"); } }
/// <summary> /// Attempts to use the data provided in packetBuilder to recreate something usefull. If we don't have enough data yet that value is set in packetBuilder. /// </summary> /// <param name="packetBuilder">The <see cref="PacketBuilder"/> containing incoming cached data</param> protected void IncomingPacketHandleHandOff(PacketBuilder packetBuilder) { try { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... checking for completed packet with " + packetBuilder.TotalBytesCached.ToString() + " bytes read."); } if (packetBuilder.TotalPartialPacketCount == 0) { throw new Exception("Executing IncomingPacketHandleHandOff when no packets exist in packetbuilder."); } //Loop until we are finished with this packetBuilder int loopCounter = 0; while (true) { //If we have ended up with a null packet at the front, probably due to some form of concatentation we can pull it off here //It is possible we have concatenation of several null packets along with real data so we loop until the firstByte is greater than 0 if (packetBuilder.FirstByte() == 0) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... null packet removed in IncomingPacketHandleHandOff() from " + ConnectionInfo + ", loop index - " + loopCounter.ToString()); } packetBuilder.ClearNTopBytes(1); //Reset the expected bytes to 0 so that the next check starts from scratch packetBuilder.TotalBytesExpected = 0; //If we have run out of data completely then we can return immediately if (packetBuilder.TotalBytesCached == 0) { return; } } else { //First determine the expected size of a header packet int packetHeaderSize = packetBuilder.FirstByte() + 1; //Do we have enough data to build a header? if (packetBuilder.TotalBytesCached < packetHeaderSize) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... ... more data required for complete packet header."); } //Set the expected number of bytes and then return packetBuilder.TotalBytesExpected = packetHeaderSize; return; } //We have enough for a header PacketHeader topPacketHeader; using (MemoryStream headerStream = packetBuilder.ReadDataSection(1, packetHeaderSize - 1)) topPacketHeader = new PacketHeader(headerStream, NetworkComms.InternalFixedSendReceiveOptions); //Idiot test if (topPacketHeader.PacketType == null) { throw new SerialisationException("packetType value in packetHeader should never be null"); } //We can now use the header to establish if we have enough payload data //First case is when we have not yet received enough data if (packetBuilder.TotalBytesCached < packetHeaderSize + topPacketHeader.PayloadPacketSize) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... ... more data required for complete packet payload. Expecting " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " total packet bytes."); } //Set the expected number of bytes and then return packetBuilder.TotalBytesExpected = packetHeaderSize + topPacketHeader.PayloadPacketSize; return; } //Second case is we have enough data else if (packetBuilder.TotalBytesCached >= packetHeaderSize + topPacketHeader.PayloadPacketSize) { //We can either have exactly the right amount or even more than we were expecting //We may have too much data if we are sending high quantities and the packets have been concatenated //no problem!! SendReceiveOptions incomingPacketSendReceiveOptions = IncomingPacketSendReceiveOptions(topPacketHeader); if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Debug("Received packet of type '" + topPacketHeader.PacketType + "' from " + ConnectionInfo + ", containing " + packetHeaderSize.ToString() + " header bytes and " + topPacketHeader.PayloadPacketSize.ToString() + " payload bytes."); } //If this is a reserved packetType we call the method inline so that it gets dealt with immediately bool isReservedType = false; foreach (var tName in NetworkComms.reservedPacketTypeNames) { //isReservedType |= topPacketHeader.PacketType == tName; if (topPacketHeader.PacketType == tName) { isReservedType = true; break; } } //Only reserved packet types get completed inline if (isReservedType) { #if WINDOWS_PHONE var priority = QueueItemPriority.Normal; #else var priority = (QueueItemPriority)Thread.CurrentThread.Priority; #endif PriorityQueueItem item = new PriorityQueueItem(priority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.PayloadPacketSize), incomingPacketSendReceiveOptions); if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' inline. Loop index - " + loopCounter.ToString()); } NetworkComms.CompleteIncomingItemTask(item); } else { QueueItemPriority itemPriority = (incomingPacketSendReceiveOptions.Options.ContainsKey("ReceiveHandlePriority") ? (QueueItemPriority)Enum.Parse(typeof(QueueItemPriority), incomingPacketSendReceiveOptions.Options["ReceiveHandlePriority"]) : QueueItemPriority.Normal); PriorityQueueItem item = new PriorityQueueItem(itemPriority, this, topPacketHeader, packetBuilder.ReadDataSection(packetHeaderSize, topPacketHeader.PayloadPacketSize), incomingPacketSendReceiveOptions); //QueueItemPriority.Highest is the only priority that is executed inline #if !WINDOWS_PHONE if (itemPriority == QueueItemPriority.Highest) { if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... handling packet type '" + topPacketHeader.PacketType + "' with priority HIGHEST inline. Loop index - " + loopCounter.ToString()); } NetworkComms.CompleteIncomingItemTask(item); } else { int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item); if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + "."); } } #else int threadId = NetworkComms.CommsThreadPool.EnqueueItem(item.Priority, NetworkComms.CompleteIncomingItemTask, item); if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace(" ... added completed " + item.PacketHeader.PacketType + " packet to thread pool (Q:" + NetworkComms.CommsThreadPool.QueueCount.ToString() + ", T:" + NetworkComms.CommsThreadPool.CurrentNumTotalThreads.ToString() + ", I:" + NetworkComms.CommsThreadPool.CurrentNumIdleThreads.ToString() + ") with priority " + itemPriority.ToString() + (threadId > 0 ? ". Selected threadId=" + threadId.ToString() : "") + ". Loop index=" + loopCounter.ToString() + "."); } #endif } //We clear the bytes we have just handed off if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Trace("Removing " + (packetHeaderSize + topPacketHeader.PayloadPacketSize).ToString() + " bytes from incoming packet buffer from connection with " + ConnectionInfo + "."); } packetBuilder.ClearNTopBytes(packetHeaderSize + topPacketHeader.PayloadPacketSize); //Reset the expected bytes to 0 so that the next check starts from scratch packetBuilder.TotalBytesExpected = 0; //If we have run out of data completely then we can return immediately if (packetBuilder.TotalBytesCached == 0) { return; } } else { throw new CommunicationException("This should be impossible!"); } } loopCounter++; } } catch (Exception ex) { //Any error, throw an exception. if (NetworkComms.LoggingEnabled) { NetworkComms.Logger.Fatal("A fatal exception occured in IncomingPacketHandleHandOff(), connection with " + ConnectionInfo + " be closed. See log file for more information."); } NetworkComms.LogError(ex, "CommsError"); CloseConnection(true, 45); } }
/// <summary> /// Performs whatever functions we might so desire when we receive an incoming ChatMessage /// </summary> /// <param name="header">The PacketHeader corresponding with the received object</param> /// <param name="connection">The Connection from which this object was received</param> /// <param name="incomingMessage">The incoming ChatMessage we are after</param> protected override void HandleIncomingChatMessage(PacketHeader header, Connection connection, ChatMessage incomingMessage) { //We call the base that handles everything base.HandleIncomingChatMessage(header, connection, incomingMessage); //Once the base is complete we refresh the messages from box RefreshMessagesFromBox(); }
/// <summary> /// UDP - The response to a DFS_KnownPeersRequest /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="peerList"></param> private static void KnownPeersUpdate(PacketHeader packetHeader, Connection connection, KnownPeerEndPoints peerList) { try { DistributedItem currentItem = null; if (DFS.loggingEnabled) DFS.Logger.Trace("Handling 'DFS_KnownPeersUpdate' from " + connection.ToString() + " containing " + peerList.PeerEndPoints.Length + " peers."); lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(peerList.ItemChecksm)) currentItem = swarmedItemsDict[peerList.ItemChecksm]; } if (currentItem != null) { //If we have some unknown peers we can request an update from them as well foreach (string peerContactInfo in peerList.PeerEndPoints) { try { IPEndPoint peerEndPoint = IPTools.ParseEndPointFromString(peerContactInfo); //We don't want to contact existing peers as this has already been done by SwarmChunkAvailability.UpdatePeerAvailability //We don't want to contact ourselves and for now that includes anything having the same ip as us if (!currentItem.SwarmChunkAvailability.PeerExistsInSwarm(peerEndPoint) && currentItem.SwarmChunkAvailability.PeerContactAllowed(ShortGuid.Empty, peerEndPoint, false)) { currentItem.AddBuildLogLine("Contacting " + peerContactInfo + " for a DFS_ChunkAvailabilityRequest from within KnownPeersUpdate."); UDPConnection.SendObject("DFS_ChunkAvailabilityRequest", peerList.ItemChecksm, peerEndPoint, nullCompressionSRO); } } catch (CommsException) { if (DFS.loggingEnabled) DFS.Logger.Trace("Removing " + peerContactInfo + " from item swarm due to CommsException."); currentItem.AddBuildLogLine("Removing " + peerContactInfo + " from item swarm due to CommsException."); } catch (Exception ex) { LogTools.LogException(ex, "UpdatePeerChunkAvailabilityError_3"); } } } else { if (DFS.loggingEnabled) DFS.Logger.Trace("Received 'DFS_KnownPeersUpdate' data for item which does not exist locally."); } } catch (CommsException) { //LogTools.LogException(e, "CommsError_IncomingChunkAvailabilityRequest"); } catch (Exception e) { LogTools.LogException(e, "Error_KnownPeersUpdate"); } }
private void ReceivedMessageTcpString(PacketHeader header, ConnectionTcp connection, string message) { try { Console.WriteLine("Paired TCP connection for {0}: {1}", message, connection.ConnectionInfo.RemoteEndPoint); _Clients.SetPlayerConnectionTcp(Convert.ToUInt16(message), connection); connection.SendObject("Message", "Connected"); } catch (Exception ex) { ExceptionHandler.LogException(ex); } }
/// <summary> /// TCP - Received by this DFS if a server is telling this instance to build a local file /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="assemblyConfig"></param> private static void IncomingLocalItemBuild(PacketHeader packetHeader, Connection connection, ItemAssemblyConfig assemblyConfig) { //We start the build in the DFS task factory as it will be a long lived task //BuildTaskFactory.StartNew(() => Action assembleAction = new Action(() => { DistributedItem newItem = null; byte[] itemBytes = null; try { if (assemblyConfig == null) throw new NullReferenceException("AssemblyConfig should not be null."); if (DFS.loggingEnabled) DFS._DFSLogger.Debug("IncomingLocalItemBuild from " + connection + " for item " + assemblyConfig.CompleteDataCheckSum + "."); //We check to see if we already have the necessary file locally lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(assemblyConfig.CompleteDataCheckSum)) { if (swarmedItemsDict[assemblyConfig.CompleteDataCheckSum].Data.ItemBytesLength != assemblyConfig.TotalItemSizeInBytes) throw new Exception("Possible MD5 conflict detected."); else newItem = swarmedItemsDict[assemblyConfig.CompleteDataCheckSum]; } else { newItem = new DistributedItem(assemblyConfig); swarmedItemsDict.Add(assemblyConfig.CompleteDataCheckSum, newItem); } } //Ensure all possible local listeners are added here List<ConnectionInfo> seedConnectionInfoList = (from current in Connection.ExistingLocalListenEndPoints(ConnectionType.TCP) select new ConnectionInfo(ConnectionType.TCP, NetworkComms.NetworkIdentifier, current, true)).ToList(); foreach (ConnectionInfo info in seedConnectionInfoList) newItem.SwarmChunkAvailability.AddOrUpdateCachedPeerChunkFlags(info, newItem.SwarmChunkAvailability.PeerChunkAvailability(NetworkComms.NetworkIdentifier), newItem.SwarmChunkAvailability.PeerIsSuperPeer(NetworkComms.NetworkIdentifier), false); //Build the item from the swarm //If the item is already complete this will return immediately newItem.AssembleItem((int)(ItemBuildTimeoutSecsPerMB * (assemblyConfig.TotalItemSizeInBytes / (1024.0 * 1024.0)))); //Once complete we pass the item bytes back into network comms //If an exception is thrown we will probably not call this method, timeouts in other areas should then handle and can restart the build. if (newItem.LocalItemComplete() && assemblyConfig.CompletedPacketType != "") { if (DFS.loggingEnabled) DFS._DFSLogger.Debug("IncomingLocalItemBuild completed for item with MD5 " + assemblyConfig.CompleteDataCheckSum + ". Item build target is " + assemblyConfig.ItemBuildMode + "."); itemBytes = newItem.GetCompletedItemBytes(); } else if (assemblyConfig.CompletedPacketType != "") RemoveItem(assemblyConfig.CompleteDataCheckSum); if (DFS.loggingEnabled) { Exception exceptionToLogWith = new Exception("Build completed successfully. Logging was enabled so saving build log."); string fileName = "DFSItemBuildLog_" + newItem.ItemIdentifier + "_" + NetworkComms.NetworkIdentifier; if (newItem != null) LogTools.LogException(exceptionToLogWith, fileName, newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; })); else LogTools.LogException(exceptionToLogWith, fileName, "newItem==null so no build log was available."); } } catch (ObjectDisposedException) { //The item was closed during assemble, no need to log an errors here RemoveItem(assemblyConfig.CompleteDataCheckSum); } catch (CommsException e) { //Crap an error has happened, let people know we probably don't have a good file RemoveItem(assemblyConfig.CompleteDataCheckSum); //connection.CloseConnection(true, 30); //LogTools.LogException(e, "CommsError_IncomingLocalItemBuild"); if (newItem != null) LogTools.LogException(e, "Error_IncomingLocalItemBuildComms", newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; })); else LogTools.LogException(e, "Error_IncomingLocalItemBuildComms", "newItem==null so no build log was available."); } catch (Exception e) { //Crap an error has happened, let people know we probably don't have a good file RemoveItem(assemblyConfig.CompleteDataCheckSum); //connection.CloseConnection(true, 31); if (newItem != null) LogTools.LogException(e, "Error_IncomingLocalItemBuild", newItem.BuildLog().Aggregate(Environment.NewLine, (p, q) => { return p + Environment.NewLine + q; })); else LogTools.LogException(e, "Error_IncomingLocalItemBuild", "newItem==null so no build log was available."); } //finally //{ //Putting any code here appears to cause a sigsegv fault on leaving the finally in mono //Just moved the code out to below as it makes no difference //} //Regardless of if the item completed we call the necessary packet handlers //If there was a build error we just pass null data to the handlers so that the errors can get called up the relevant stack traces. try { PacketHeader itemPacketHeader = new PacketHeader(assemblyConfig.CompletedPacketType, newItem == null ? 0 : newItem.Data.ItemBytesLength); //We set the item checksum so that the entire distributed item can be easily retrieved later itemPacketHeader.SetOption(PacketHeaderStringItems.PacketIdentifier, newItem == null ? "" : newItem.ItemTypeStr + "|" + newItem.ItemIdentifier + "|" + newItem.Data.CompleteDataCheckSum); var dataStream = (itemBytes == null ? new MemoryStream(new byte[0], 0, 0, false, true) : new MemoryStream(itemBytes, 0, itemBytes.Length, false, true)); var sendRecieveOptions = new SendReceiveOptions<NullSerializer>(new Dictionary<string, string>()); NetworkComms.TriggerAllPacketHandlers(itemPacketHeader, connection, dataStream, sendRecieveOptions); } catch (Exception ex) { LogTools.LogException(ex, "Error_IncomingLocalItemBuildFinal"); } }); if (BuildTaskFactory == null) LogTools.LogException(new NullReferenceException("BuildTaskFactory is null in IncomingLocalItemBuild"), "IncomingLocalBuildError"); else //Thread buildThread = new Thread(buildAction); //buildThread.Name = "DFS_" + assemblyConfig.ItemIdentifier + "_Build"; //buildThread.Start(); BuildTaskFactory.StartNew(assembleAction); }
/// <summary> /// TCP - A remote peer has request a push of the provided itemCheckSums. This method is used primarily when in repeater mode /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="itemCheckSums"></param> private static void RequestLocalItemBuilds(PacketHeader packetHeader, Connection connection, string[] itemCheckSums) { try { DistributedItem[] selectedItems = null; lock (globalDFSLocker) selectedItems = (from current in swarmedItemsDict where itemCheckSums.Contains(current.Key) select current.Value).ToArray(); if (selectedItems !=null && selectedItems.Length > 0) foreach(DistributedItem item in selectedItems) DFS.PushItemToPeer(connection, item, ""); } catch (CommsException) { //LogTools.LogException(e, "CommsError_IncomingLocalItemBuild"); } catch (Exception e) { LogTools.LogException(e, "Error_RequestLocalItemBuild"); } }
/// <summary> /// UDP - Received when a peer request a chunk /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="incomingRequest"></param> private static void IncomingChunkInterestRequest(PacketHeader packetHeader, Connection connection, ChunkAvailabilityRequest incomingRequest) { try { //A peer has requested a specific chunk of data, we will only provide it if we are not already providing it to someone else DateTime startTime = DateTime.Now; //Console.WriteLine("... ({0}) received request for chunk {1} from {2}.", DateTime.Now.ToString("HH:mm:ss.fff"), incomingRequest.ChunkIndex, sourceConnectionId); if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingChunkInterestRequest from " + connection + " for " + incomingRequest.ItemCheckSum + ", chunkIndex " + incomingRequest.ChunkIndex + "."); DistributedItem selectedItem = null; lock (globalDFSLocker) if (swarmedItemsDict.ContainsKey(incomingRequest.ItemCheckSum)) selectedItem = swarmedItemsDict[incomingRequest.ItemCheckSum]; if (selectedItem == null || (selectedItem != null && selectedItem.ItemClosed)) { //First reply and say the peer can't have the requested data. This prevents a request timing out connection.SendObject("DFS_ChunkAvailabilityInterestReplyInfo", new ChunkAvailabilityReply(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, incomingRequest.ChunkIndex, ChunkReplyState.ItemOrChunkNotAvailable), nullCompressionSRO); //Inform peer that we don't actually have the requested item UDPConnection.SendObject("DFS_ItemRemovalUpdate", new ItemRemovalUpdate(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, false), (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, nullCompressionSRO); if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... item not available locally, sent DFS_ItemRemovalUpdate."); } else { //A little request validation if (incomingRequest.ChunkIndex > selectedItem.Data.TotalNumChunks) throw new InvalidDataException("The incoming request wanted chunk #" + incomingRequest.ChunkIndex + " when the selected item only has " + selectedItem.Data.TotalNumChunks + "chunks."); if (!selectedItem.ChunkAvailableLocally(incomingRequest.ChunkIndex)) { //First reply and say the peer can't have the requested data. This prevents a request timing out connection.SendObject("DFS_ChunkAvailabilityInterestReplyInfo", new ChunkAvailabilityReply(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, incomingRequest.ChunkIndex, ChunkReplyState.ItemOrChunkNotAvailable), nullCompressionSRO); //If the peer thinks we have a chunk we don't we send them an update so that they are corrected UDPConnection.SendObject("DFS_PeerChunkAvailabilityUpdate", new PeerChunkAvailabilityUpdate(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, selectedItem.SwarmChunkAvailability.PeerChunkAvailability(NetworkComms.NetworkIdentifier)), (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, nullCompressionSRO); if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... requested chunk not available, sent DFS_PeerChunkAvailabilityUpdate."); } else { //If we are a super peer we always have to respond to the request if (HostInfo.IP.AverageNetworkLoadOutgoing(10) > DFS.PeerBusyNetworkLoadThreshold && !selectedItem.SwarmChunkAvailability.PeerIsSuperPeer(NetworkComms.NetworkIdentifier)) { //We can return a busy reply if we are currently experiencing high demand connection.SendObject("DFS_ChunkAvailabilityInterestReplyInfo", new ChunkAvailabilityReply(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, incomingRequest.ChunkIndex, ChunkReplyState.PeerBusy), nullCompressionSRO); if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... peer busy, sent busy response."); } else { StreamTools.StreamSendWrapper chunkData = selectedItem.GetChunkDataStream(incomingRequest.ChunkIndex); if (DFS.loggingEnabled) DFS._DFSLogger.Trace("Pushing chunkData to " + connection + " for item:" + incomingRequest.ItemCheckSum + ", chunkIndex:" + incomingRequest.ChunkIndex + "."); //We identify the data using the itemchecksum, the requested chunk index, and to unique identify this request from possible duplicates //we append the requesting peer request index. string packetIdentifier = selectedItem.Data.CompleteDataCheckSum + "-" + incomingRequest.ChunkIndex + "-" + incomingRequest.RequestNumIndex; //This is received via UDP but we want to reply using TCP to ensure delivery of the data var clientTCPConnection = TCPConnection.GetConnection(new ConnectionInfo(connection.ConnectionInfo.RemoteEndPoint)); //Send using a custom packet so that we can add the packet identifier using (Packet sendPacket = new Packet("DFS_ChunkAvailabilityInterestReplyData", chunkData, nullCompressionSRO)) { sendPacket.PacketHeader.SetOption(PacketHeaderStringItems.PacketIdentifier, packetIdentifier); clientTCPConnection.SendPacket<StreamTools.StreamSendWrapper>(sendPacket); } if (DFS.loggingEnabled) DFS._DFSLogger.Trace("Pushing chunkInfo to " + connection + " for item:" + incomingRequest.ItemCheckSum + ", chunkIndex:" + incomingRequest.ChunkIndex + "."); clientTCPConnection.SendObject("DFS_ChunkAvailabilityInterestReplyInfo", new ChunkAvailabilityReply(NetworkComms.NetworkIdentifier, incomingRequest.ItemCheckSum, incomingRequest.ChunkIndex, packetIdentifier), nullCompressionSRO); lock (TotalNumReturnedChunkRequestsLocker) TotalNumReturnedChunkRequests++; if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... IncomingChunkInterestRequest completed with data in " + (DateTime.Now - startTime).TotalSeconds.ToString("0.0") + " seconds."); } } } } catch (ObjectDisposedException) { //This happens if we dispose the DFS item during this method execution if (loggingEnabled) Logger.Warn("Prevented ObjectDisposedException in IncomingChunkInterestRequest"); } catch (ConnectionSetupException) { //Ignore, the peer is offline } catch (CommunicationException) { //Ignore, connection is probably closed } catch (ConnectionSendTimeoutException) { //Ignore, the peer is suspended } catch (DuplicateConnectionException) { //Ignore, two peers tried to connect simultaneously } catch (ConnectionShutdownException) { //Ignore, the peer disconnected } catch (CommsException e) { //Something f****d happened. //Console.WriteLine("IncomingChunkInterestRequestError. Error logged."); LogTools.LogException(e, "CommsError_IncomingChunkInterestRequest"); } catch (Exception e) { LogTools.LogException(e, "Error_IncomingChunkInterestRequest"); } }
private void MethodMessageReceived(PacketHeader header, Connection connection, string message) { logging.AddToLog("\nA message was recieved from " + connection.ToString() + " which said '" + message + "'.", true); }
/// <summary> /// TCP - Received when a peer sends us the data portion of a chunk possibly following a request /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="incomingData"></param> private static void IncomingChunkInterestReplyData(PacketHeader packetHeader, Connection connection, byte[] incomingData) { try { if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingChunkInterestReplyData from " + connection + " containing " + incomingData.Length + " bytes."); if (connection.ConnectionInfo.ConnectionType != ConnectionType.TCP) throw new Exception("IncomingChunkInterestReplyData should only be received using TCP."); ChunkAvailabilityReply existingChunkAvailabilityReply = null; try { lock (chunkDataCacheLocker) { if (!chunkDataCache.ContainsKey(connection.ConnectionInfo.NetworkIdentifier)) chunkDataCache.Add(connection.ConnectionInfo.NetworkIdentifier, new Dictionary<string, ChunkDataWrapper>()); if (!packetHeader.ContainsOption(PacketHeaderLongItems.PacketSequenceNumber)) throw new Exception("The dataSequenceNumber option appears to missing from the packetHeader. What has been changed?"); string packetIdentifier = packetHeader.PacketIdentifier; if (packetIdentifier == null) throw new ArgumentException("The packetHeader.PacketIdentifier should not be null."); //If we already have the info then we can finish this chunk off if (chunkDataCache[connection.ConnectionInfo.NetworkIdentifier].ContainsKey(packetIdentifier)) { if (chunkDataCache[connection.ConnectionInfo.NetworkIdentifier][packetIdentifier] == null) throw new Exception("An entry existed for the desired dataSequenceNumber but the entry was null."); else if (chunkDataCache[connection.ConnectionInfo.NetworkIdentifier][packetIdentifier].ChunkAvailabilityReply == null) throw new Exception("An entry existed for the desired ChunkAvailabilityReply but the entry was null."+ " This exception can be thrown if the 'IncomingChunkInterestReplyData' packet handler has been added more than once."); //The info beat the data so we handle it here existingChunkAvailabilityReply = chunkDataCache[connection.ConnectionInfo.NetworkIdentifier][packetIdentifier].ChunkAvailabilityReply; existingChunkAvailabilityReply.SetChunkData(incomingData); chunkDataCache[connection.ConnectionInfo.NetworkIdentifier].Remove(packetIdentifier); if (chunkDataCache[connection.ConnectionInfo.NetworkIdentifier].Count == 0) chunkDataCache.Remove(connection.ConnectionInfo.NetworkIdentifier); } else { //If we don't have the info we just need to log the data chunkDataCache[connection.ConnectionInfo.NetworkIdentifier].Add(packetIdentifier, new ChunkDataWrapper(packetIdentifier, incomingData)); if (DFS.loggingEnabled) DFS._DFSLogger.Trace("Added ChunkData to chunkDataCache from " + connection + ", packet identifier:" + packetIdentifier + " , containing " + incomingData.Length + " bytes."); } } //Only true if we have both the data and info if (existingChunkAvailabilityReply != null) { existingChunkAvailabilityReply.SetSourceConnectionInfo(connection.ConnectionInfo); DistributedItem item = null; lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(existingChunkAvailabilityReply.ItemCheckSum)) item = swarmedItemsDict[existingChunkAvailabilityReply.ItemCheckSum]; } if (item != null) item.HandleIncomingChunkReply(existingChunkAvailabilityReply); } } catch (Exception ex) { LogTools.LogException(ex, "Error_IncomingChunkInterestReplyDataInner"); } CheckForChunkDataCacheTimeouts(); } catch (Exception e) { LogTools.LogException(e, "Error_IncomingChunkInterestReplyData"); } }
private void CommandMessageReceived(PacketHeader header, Connection connection, string message) { string[] param = message.Split('|'); if (param[2].Trim() == Common.ComputerName) { this.Log.Info("CMDLINE received: " + param[0].Trim() + " - " + param[1].Trim()); Process pr = new Process(); pr.StartInfo.FileName = param[0].Trim(); pr.StartInfo.Arguments = param[1].Trim(); pr.Start(); } }
/// <summary> /// UDP and TCP - Received when a peer sends us a chunk data information possibly following a request /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="incomingReply"></param> private static void IncomingChunkInterestReplyInfo(PacketHeader packetHeader, Connection connection, ChunkAvailabilityReply incomingReply) { try { ConnectionInfo incomingConnectionInfo = new ConnectionInfo(connection.ConnectionInfo.ConnectionType, incomingReply.SourceNetworkIdentifier, connection.ConnectionInfo.RemoteEndPoint, true); if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingChunkInterestReplyInfo from " + connection + " for item " + incomingReply.ItemCheckSum + ", chunkIndex " + incomingReply.ChunkIndex + "."); if (incomingReply.ReplyState == ChunkReplyState.DataIncluded && incomingReply.PacketIdentifier == null) throw new ArgumentNullException("The specified packet identifier cannot be null."); DistributedItem item = null; lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(incomingReply.ItemCheckSum)) item = swarmedItemsDict[incomingReply.ItemCheckSum]; } if (item != null) { //Do we have the data yet? bool handleReply = false; lock (chunkDataCacheLocker) { //We generally expect the data to arrive first, but we handle both situations anyway //Realistic testing across a 100MB connection shows that we already have the data 90.1% of the time if (incomingReply.ReplyState == ChunkReplyState.DataIncluded && chunkDataCache.ContainsKey(incomingReply.SourceNetworkIdentifier) && chunkDataCache[incomingReply.SourceNetworkIdentifier].ContainsKey(incomingReply.PacketIdentifier)) { incomingReply.SetChunkData(chunkDataCache[incomingReply.SourceNetworkIdentifier][incomingReply.PacketIdentifier].Data); chunkDataCache[incomingReply.SourceNetworkIdentifier].Remove(incomingReply.PacketIdentifier); if (DFS.loggingEnabled) DFS._DFSLogger.Debug("Completed ChunkAvailabilityReply using data in chunkDataCache from " + connection + ", packet identifier:" + incomingReply.PacketIdentifier + "."); if (chunkDataCache[incomingReply.SourceNetworkIdentifier].Count == 0) chunkDataCache.Remove(incomingReply.SourceNetworkIdentifier); } else if (incomingReply.ReplyState == ChunkReplyState.DataIncluded) { //We have beaten the data, we will add the chunk availability reply instead and wait, letting the incoming data trigger the handle if (!chunkDataCache.ContainsKey(incomingReply.SourceNetworkIdentifier)) chunkDataCache.Add(incomingReply.SourceNetworkIdentifier, new Dictionary<string,ChunkDataWrapper>()); chunkDataCache[incomingReply.SourceNetworkIdentifier].Add(incomingReply.PacketIdentifier, new ChunkDataWrapper(incomingReply)); if (DFS.loggingEnabled) DFS._DFSLogger.Debug("Added ChunkAvailabilityReply to chunkDataCache (awaiting data) from " + connection + ", packet identifier:" + incomingReply.PacketIdentifier + "."); } //We decide if we are going to handle the data within the lock to avoid possible handle contention if (incomingReply.ChunkDataSet || incomingReply.ReplyState != ChunkReplyState.DataIncluded) handleReply = true; } if (handleReply) { incomingReply.SetSourceConnectionInfo(incomingConnectionInfo); item.HandleIncomingChunkReply(incomingReply); } } } catch (Exception e) { LogTools.LogException(e, "Error_IncomingChunkInterestReplyInfo"); } }
private void MethodMessageReceived(PacketHeader header, Connection connection, string message) { string[] items = message.Split('|'); OSAEMethod method = new OSAEMethod(items[2].Trim(), "", items[0].Trim(), items[3].Trim(), items[4].Trim(), items[5].Trim(), items[1].Trim()); if (method.ObjectName == "SERVICE-" + Common.ComputerName) { if (method.MethodName == "RESTART PLUGIN") { foreach (Plugin p in plugins) { if (p.PluginName == method.Parameter1) { OSAEObject obj = OSAEObjectManager.GetObjectByName(p.PluginName); if (obj != null) { disablePlugin(p); enablePlugin(p); } } } } } else { foreach (Plugin plugin in plugins) { if (plugin.Enabled == true && (method.Owner.ToLower() == plugin.PluginName.ToLower() || method.ObjectName.ToLower() == plugin.PluginName.ToLower())) { plugin.ExecuteCommand(method); } } } }
/// <summary> /// UDP - A remote peer is announcing that it has an updated availability of chunks /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="updateDetails"></param> private static void IncomingPeerChunkAvailabilityUpdate(PacketHeader packetHeader, Connection connection, PeerChunkAvailabilityUpdate updateDetails) { try { if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingPeerChunkAvailabilityUpdate from " + connection + " for item " + updateDetails.ItemCheckSum + "(" + updateDetails.ChunkFlags.NumCompletedChunks() + ")."); DistributedItem selectedItem = null; lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(updateDetails.ItemCheckSum)) selectedItem = swarmedItemsDict[updateDetails.ItemCheckSum]; } if (selectedItem != null) { ConnectionInfo connectionInfo = new ConnectionInfo(ConnectionType.TCP, updateDetails.SourceNetworkIdentifier, connection.ConnectionInfo.RemoteEndPoint, true); selectedItem.SwarmChunkAvailability.AddOrUpdateCachedPeerChunkFlags(connectionInfo, updateDetails.ChunkFlags); selectedItem.AddBuildLogLine("Updated chunk flags for " + connectionInfo); } else //Inform peer that we don't actually have the requested item so that it won't bother us again //connection.SendObject("DFS_ItemRemovalUpdate", updateDetails.ItemCheckSum); UDPConnection.SendObject("DFS_ItemRemovalUpdate", new ItemRemovalUpdate(NetworkComms.NetworkIdentifier, updateDetails.ItemCheckSum, false), (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, nullCompressionSRO); } catch (CommsException) { //Meh some comms error happened. } catch (Exception e) { LogTools.LogException(e, "Error_IncomingPeerChunkAvailabilityUpdate"); } }
private void PluginMessageReceived(PacketHeader header, Connection connection, string message) { Log.Info("<- Plugin Message: " + message); string[] arguments = message.Split('|'); foreach (Plugin p in plugins) { if (p.PluginName == arguments[0].Trim()) { Log.Info("Found Plugin: " + arguments[0].Trim() + " on " + serviceObject); OSAEObject obj = OSAEObjectManager.GetObjectByName(p.PluginName); if (obj != null) { Log.Info("Found Plugin Object for: " + arguments[0].Trim() + " on " + serviceObject); bool isSystemPlugin = false; foreach (OSAEObjectProperty p2 in obj.Properties) { if (p2.Name == "System Plugin") { if (p2.Value == "TRUE") isSystemPlugin = true; break; } } Log.Info("Plugin " + arguments[0].Trim() + " SystemPlugin = " + isSystemPlugin); if (arguments[1].Trim() == "ON" && !isSystemPlugin) { //We are only stoppeng and starting, leave enabled alone //OSAEObjectManager.ObjectUpdate(p.PluginName, p.PluginName, obj.Alias, obj.Description, obj.Type, obj.Address, obj.Container, obj.MinTrustLevel, true); try { startPlugin(p); Log.Debug("Started plugin: " + p.PluginName); } catch (Exception ex) { Log.Error("Error Starting plugin (" + p.PluginName + ")", ex); } } else if (arguments[1].Trim() == "OFF" && !isSystemPlugin) { //OSAEObjectManager.ObjectUpdate(p.PluginName, p.PluginName, obj.Alias, obj.Description, obj.Type, obj.Address, obj.Container, obj.MinTrustLevel, false); try { stopPlugin(p); Log.Debug("Stopped plugin: " + p.PluginName); } catch (Exception ex) { Log.Error("Error stopping plugin (" + p.PluginName + ")", ex); } } } } } }
/// <summary> /// UDP - A remote peer is informing us that they no longer have an item /// </summary> /// <param name="packetHeader"></param> /// <param name="connection"></param> /// <param name="itemRemovalUpdate"></param> private static void IncomingItemRemovalUpdate(PacketHeader packetHeader, Connection connection, ItemRemovalUpdate itemRemovalUpdate) { try { if (DFS.loggingEnabled) DFS._DFSLogger.Trace("IncomingItemRemovalUpdate from " + connection + " for " + itemRemovalUpdate.ItemCheckSum + ". " + (itemRemovalUpdate.RemoveSwarmWide ? "SwamWide" : "Local Only") + "."); if (itemRemovalUpdate == null) throw new NullReferenceException("ItemRemovalUpdate was null."); if (itemRemovalUpdate.SourceNetworkIdentifier == null || itemRemovalUpdate.SourceNetworkIdentifier == ShortGuid.Empty) throw new NullReferenceException("itemRemovalUpdate.SourceNetworkIdentifier was null / empty. " + itemRemovalUpdate.SourceNetworkIdentifier != null ? itemRemovalUpdate.SourceNetworkIdentifier : ""); DistributedItem item = null; lock (globalDFSLocker) { if (swarmedItemsDict.ContainsKey(itemRemovalUpdate.ItemCheckSum)) item = swarmedItemsDict[itemRemovalUpdate.ItemCheckSum]; } if (item != null) { if (itemRemovalUpdate.RemoveSwarmWide) //If this is a swarmwide removal then we get rid of our local copy as well RemoveItem(itemRemovalUpdate.ItemCheckSum, false); else { //Delete any old references at the same time item.SwarmChunkAvailability.RemoveOldPeerAtEndPoint(itemRemovalUpdate.SourceNetworkIdentifier, (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint); //If this is not a swarm wide removal we just remove this peer from our local swarm copy item.SwarmChunkAvailability.RemovePeerIPEndPointFromSwarm(itemRemovalUpdate.SourceNetworkIdentifier, (IPEndPoint)connection.ConnectionInfo.RemoteEndPoint, true); } } else if (DFS.loggingEnabled) DFS._DFSLogger.Trace(" ... nothing removed as item not present locally."); } catch (CommsException e) { LogTools.LogException(e, "CommsError_IncomingPeerItemRemovalUpdate"); } catch (Exception e) { string commentStr = ""; if (itemRemovalUpdate != null) commentStr = "itemCheckSum:" + itemRemovalUpdate.ItemCheckSum + ", swarmWide:" + itemRemovalUpdate.RemoveSwarmWide + ", identifier" + itemRemovalUpdate.SourceNetworkIdentifier; LogTools.LogException(e, "Error_IncomingPeerItemRemovalUpdate", commentStr); } }
/// <summary> /// The handler that we wish to execute when we receive a message packet. /// </summary> /// <param name="header">The associated packet header.</param> /// <param name="connection">The connection used for the incoming packet</param> /// <param name="incomingString">The incoming data converted to a string</param> private static void HandleIncomingMessagePacket(PacketHeader header, Connection connection, string incomingString) { Console.WriteLine("\n ... Incoming message from " + connection.ToString() + " saying '" + incomingString + "'."); }
private void Constructor <payloadObjectType>(string sendingPacketTypeStr, string requestReturnPacketTypeStr, payloadObjectType payloadObject, SendReceiveOptions options, bool isNested) { if (sendingPacketTypeStr == null || sendingPacketTypeStr == "") { throw new ArgumentNullException("sendingPacketTypeStr", "The provided string can not be null or zero length."); } if (options == null) { throw new ArgumentNullException("options", "The provided SendReceiveOptions cannot be null."); } if (options.DataSerializer == null) { throw new ArgumentNullException("options", "The provided SendReceiveOptions.DataSerializer cannot be null. Consider using NullSerializer instead."); } //Check for security critical data processors //There may be performance issues here bool containsSecurityCritialDataProcessors = false; if (!options.Options.ContainsKey("UseNestedPacketType") && //We only need to perform this check if we are not already using a nested packet !isNested) //We do not perform this check within a nested packet { foreach (DataProcessor processor in options.DataProcessors) { if (processor.IsSecurityCritical) { containsSecurityCritialDataProcessors = true; break; } } } //By default the object to serialise will be the payloadObject object objectToSerialise = payloadObject; bool objectToSerialiseIsNull = false; //We only replace the null with an empty stream if this is either in the nested packet //or we will not be nesting if (objectToSerialise == null && ((!options.Options.ContainsKey("UseNestedPacketType") && !containsSecurityCritialDataProcessors) || isNested)) { #if NETFX_CORE var emptyStream = new MemoryStream(new byte[0], 0, 0, false); #else var emptyStream = new MemoryStream(new byte[0], 0, 0, false, true); #endif //If the sending object is null we set objectToSerialiseIsNull and create a zero length StreamSendWrapper //The zero length StreamSendWrapper can then be passed to any data serializers objectToSerialiseIsNull = true; objectToSerialise = new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(emptyStream, true)); } //If we need to nest this packet if ((containsSecurityCritialDataProcessors || options.Options.ContainsKey("UseNestedPacketType")) && !isNested) { //We set the objectToSerialise to a nested packet objectToSerialise = new Packet(sendingPacketTypeStr, requestReturnPacketTypeStr, payloadObject, options, true); } else if (isNested) { //Serialise the payload object into byte[] //We do not use any data processors at this stage as the object will be processed again one level higher. #if NETFX_CORE _payloadObjectBytes = options.DataSerializer.SerialiseDataObject(payloadObject).ThreadSafeStream.ToArray(); _payloadSize = _payloadObjectBytes.Length; #else NetworkCommsDotNet.Tools.StreamTools.ThreadSafeStream tempStream = options.DataSerializer.SerialiseDataObject(objectToSerialise).ThreadSafeStream; _payloadObjectBytes = tempStream.GetBuffer(); _payloadSize = (int)tempStream.Length; #endif //Set the packet header //THe nulls represent internal SendReceiveOptions and no checksum this._packetHeader = new PacketHeader(sendingPacketTypeStr, _payloadSize, null, requestReturnPacketTypeStr, null); //Set the deserialiser information in the nested packet header, excluding data processors this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(options.DataSerializer, null)); } //If we are at the top level packet we can finish off the serialisation if (!isNested) { //Set the payload stream data. if (objectToSerialiseIsNull && options.DataProcessors.Count == 0) { //Only if there are no data processors can we use a zero length array for nulls //This ensures that should there be any required padding we can include it this.payloadStream = (StreamTools.StreamSendWrapper)objectToSerialise; } else { if (objectToSerialise is Packet) { //We have to use the internal explicit serializer for nested packets (the nested data is already byte[]) this.payloadStream = NetworkComms.InternalFixedSendReceiveOptions.DataSerializer.SerialiseDataObject(objectToSerialise, options.DataProcessors, options.Options); } else { this.payloadStream = options.DataSerializer.SerialiseDataObject(objectToSerialise, options.DataProcessors, options.Options); } } //We only calculate the checkSum if we are going to use it string hashStr = null; if (NetworkComms.EnablePacketCheckSumValidation) { hashStr = StreamTools.MD5(payloadStream.ThreadSafeStream.ToArray(payloadStream.Start, payloadStream.Length)); } //Choose the sending and receiving packet type depending on if it is being used with a nested packet string _sendingPacketTypeStr; string _requestReturnPacketTypeStr = null; if (containsSecurityCritialDataProcessors || options.Options.ContainsKey("UseNestedPacketType")) { _sendingPacketTypeStr = Enum.GetName(typeof(ReservedPacketType), ReservedPacketType.NestedPacket); } else { _sendingPacketTypeStr = sendingPacketTypeStr; _requestReturnPacketTypeStr = requestReturnPacketTypeStr; } this._packetHeader = new PacketHeader(_sendingPacketTypeStr, payloadStream.Length, options, _requestReturnPacketTypeStr, hashStr); //Add an identifier specifying the serialisers and processors we have used if (objectToSerialise is Packet) { this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(NetworkComms.InternalFixedSendReceiveOptions.DataSerializer, options.DataProcessors)); } else { this._packetHeader.SetOption(PacketHeaderLongItems.SerializerProcessors, DPSManager.CreateSerializerDataProcessorIdentifier(options.DataSerializer, options.DataProcessors)); } } //Set the null data header section if required if (objectToSerialiseIsNull && ((!containsSecurityCritialDataProcessors && !options.Options.ContainsKey("UseNestedPacketType")) || isNested)) { this._packetHeader.SetOption(PacketHeaderStringItems.NullDataSection, ""); } if (NetworkComms.LoggingEnabled) { if (isNested) { NetworkComms.Logger.Trace(" ... created nested packet of type " + sendingPacketTypeStr); } else { NetworkComms.Logger.Trace(" ... created packet of type " + sendingPacketTypeStr + ". PacketObject data size is " + payloadStream.Length.ToString() + " bytes"); } } }