/// <summary> /// Event called when any client or host connection has a change in a network data collection. /// </summary> /// <param name="packet">The base packet containing the raw data.</param> /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param> private void ConnectionCollectionChanged(NetworkPacket packet, NetworkEventArgs data) { try { //Make sure the data is of the correct type. if (data.DataType == typeof(NotifyCollectionChangedEventArgs)) { //Grab the collection changed information from the data. NotifyCollectionChangedEventArgs args = data.Data as NotifyCollectionChangedEventArgs; //Check if we have the source collection whose items was changed. if (_registeredObjects.ContainsKey(data.NetworkDataId)) { //Get the source collection we want to manipulate IList collection = _registeredObjects[data.NetworkDataId] as IList; //Disable the listener for this object while we do our changes. ListenerDisable((INetworkData)collection); //apply the changes that occured at the client/host to our collection. switch (args.Action) { case NotifyCollectionChangedAction.Add: for (int i = 0; i < args.NewItems.Count; i++) collection.Insert(args.NewStartingIndex + i, args.NewItems[i]); break; case NotifyCollectionChangedAction.Move: for (int i = 0; i < args.NewItems.Count; i++) { object temp = collection[args.OldStartingIndex + (args.OldStartingIndex > args.NewStartingIndex ? i : 0)]; collection.Remove(temp); collection.Insert(args.NewStartingIndex + i, temp); } break; case NotifyCollectionChangedAction.Remove: for (int i = 0; i < args.OldItems.Count; i++) collection.RemoveAt(args.OldStartingIndex + i); break; case NotifyCollectionChangedAction.Replace: for (int i = 0; i < args.NewItems.Count; i++) collection[args.OldStartingIndex + i] = args.NewItems[i]; break; case NotifyCollectionChangedAction.Reset: collection.Clear(); break; } //Enable the listener for our collection. ListenerEnable((INetworkData)collection); //Forward if necessary. data.Forward(); } else if (OnNotificationOccured != null) OnNotificationOccured(data, string.Format("A CollectionChanged packet was received for a collection on a network id but the network id object was not found in registered objects.")); } else if (OnNotificationOccured != null) OnWarningOccured(data, new Warning(string.Format("A network packet for collection changed was received but that data was of an invalid type. Expected a type of '{0}' but received '{1}'.", typeof(NotifyCollectionChangedEventArgs).FullName, data.DataType.FullName))); } catch (Exception e) { ThrowException(data, e); } }
/// <summary> /// Event that is called automatically when a NetworkRequest was recieved. /// </summary> /// <param name="packet">The base packet containing the raw data.</param> /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param> private void ReceivedNetworkRequest(NetworkPacket packet, NetworkEventArgs data) { //Prelimenary checking on whether the data is of correct type if (data.DataType == typeof(RequestNetworkData)) { // The data passed over the network is a real Request. Processing the request. try { //Create the response for the request and pass in all data of the request over to the //the response. This is done so the InternalName as well as other data is passed over. RequestNetworkData response = new RequestNetworkData(data.Data as RequestNetworkData); //Start processing the request. switch (response.RequestType) { case RequestNetworkDataType.RequestType: //The connection is requesting a data of specific type. Search the registered //objects for any objects that fit the description. for (int i = 0; i < _registeredObjects.Count; i++) if (_registeredObjects.ElementAt(i).Value.GetType().FullName == response.ClassTypeName) { response.Data = _registeredObjects.ElementAt(i).Value; break; } break; case RequestNetworkDataType.RequestName: //The connection is requesting name for it's object. Pass in a random //generated identifier. response.NetworkId = GetNewNetworkId(response.ClassTypeName); break; case RequestNetworkDataType.RequestData: //The connection is requesting a data with specific NetworkId. //Return the object containing that NetworkId. response.Data = this._registeredObjects[response.NetworkId]; break; } //Send the response over the network to the client/host. _network.SendSingleRawEvent((int)CorePacketCode.NetworkDataRequestResponse, new Serialiser(true).Serialise(response), packet.Source); } catch (Exception e) { //An unknown error occured. Since this is not critical part of the NetworkLibrary we //pass it on as a Warning. if (OnWarningOccured != null) OnWarningOccured(this, new Warning("A network request was received but an unknown error occured while processing the request.", e)); } } //Received a packet containing the code for a Request but the data was of an invalid type. //Since this is not a critical part of the NetworkLibrary we pass it on as a Warning. else if (OnWarningOccured != null) OnWarningOccured(this, new Warning("A network request was received but was of an invalid format. Request was truncated.")); }
/// <summary> /// Event that is called automatically when receiving a response to a Network Request. /// </summary> /// <param name="packet">The base packet containing the raw data.</param> /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param> private void ReceivedNetworkRequestResponse(NetworkPacket packet, NetworkEventArgs data) { //Prelimenary checking on whether the data is of correct type if (data.DataType == typeof(RequestNetworkData)) { // The data passed over the network is a real Response. Processing the response. try { //Retreave the original request that was the source of the response. RequestNetworkData internalRequest = _requestedData[(data.Data as RequestNetworkData).InternalName]; //Pass all data retreived from the response into the request. internalRequest.NetworkId = (data.Data as RequestNetworkData).NetworkId; internalRequest.Data = (data.Data as RequestNetworkData).Data; //Check whether the request was requesting data or type of an object. //If it is, we register into our local NetworkLibrary automatically. if ((internalRequest.RequestType == RequestNetworkDataType.RequestData || internalRequest.RequestType == RequestNetworkDataType.RequestType) && internalRequest.Data != null) //The request was requesting data. Registering it automatically. RegisterRecursive(internalRequest.Data as INetworkData); lock (internalRequest) { //This is important. In many cases when processing data in the NetworkLibrary and data //needs to be requested, the request is sent and the thread that is doing the processing //is put on sleep. With this we send a pulse into the thread to wake it up so it can continue //on the processing and finish the process it started. Monitor.Pulse(internalRequest); } //Remove the request from our collection. Since the request has been sent, processed and finished //we don't need it anymore. _requestedData.Remove(internalRequest.InternalName); } catch (Exception e) { //An unknown error occured. Since this could result in a method or a thread being paused forever //we pass it on as a real Exception. ThrowException(this, new Exception("A network response was received but an unknown error occured while processing the request.", e)); } } //Received a packet containing the code for a Request but the data was of an invalid type. //Since this could be random junk we pass it on as a Warning. else if (OnWarningOccured != null) OnWarningOccured(this, new Warning("A network request response was received but was of an invalid format. Request was truncated.")); }
/// <summary> /// Send a packet over the network. /// </summary> /// <param name="packet">The source packet to transmit over.</param> /// <param name="excludeList">A list of all the clients who will not recieve the packet. Only used for the host.</param> protected override void SendPacket(NetworkPacket packet, params object[] excludeList) { _networkConnection.SendPacket(packet, null); }
/// <summary> /// Parse an incoming string from an incoming packet and return a specialised NetworkEventArgs. /// </summary> /// <param name="item">The packet to parse.</param> /// <returns>Specialised NetworkEventArgs.</returns> public NetworkEventArgs ParsePacket(NetworkPacket packet) { //Split the message into maximum 6 parts so we can extract it's data. The format is as follows: //networkid:collectionChangedAction:startingIndexForNewItems:startingIndexForOldItems:ListOfItemsRemovedOrAdded string[] data = packet.Message.Split(new char[] { ':' }, 6); //Make sure the maximum length was archieved. if (data.Length == 6) { //Get the data handler. INetworkDataHandler dataHandler = ObjectFactory.GetInstance<INetworkDataHandler>(); //Make sure we have the item whose collection was changed. if (dataHandler.RegisteredObjects.ContainsKey(data[0])) { //Create the holder for our results. NetworkEventArgs result = new NetworkEventArgs(packet); //Assign the relevant values. result.NetworkDataId = data[0]; IList itemList; int newIndex, oldIndex, oldCount, intAction; try { //Deserialise and convert the data to it's correct form. itemList = new Serialiser().Deserialise(data[5]) as IList; intAction = Convert.ToInt32(data[1]); newIndex = Convert.ToInt32(data[2]); oldIndex = Convert.ToInt32(data[3]); oldCount = Convert.ToInt32(data[4]); } catch (Exception e) { if (OnWarningOccured != null) OnWarningOccured(packet, new Warning("An unknown error occured while deserialising a collection changed packet that was received. Message received: " + e.Message, e)); return null; } NotifyCollectionChangedAction action = (NotifyCollectionChangedAction)intAction; //Create a new instance of notify collection changed that contains the relevant //information about the changes in the collection. switch (action) { case NotifyCollectionChangedAction.Add: result.Data = new NotifyCollectionChangedEventArgs(action, itemList, newIndex); break; case NotifyCollectionChangedAction.Move: result.Data = new NotifyCollectionChangedEventArgs(action, itemList, newIndex, oldIndex); break; case NotifyCollectionChangedAction.Remove: result.Data = new NotifyCollectionChangedEventArgs(action, itemList, oldIndex); break; case NotifyCollectionChangedAction.Replace: result.Data = new NotifyCollectionChangedEventArgs(action, itemList, new bool[oldCount], newIndex); break; case NotifyCollectionChangedAction.Reset: result.Data = new NotifyCollectionChangedEventArgs(action); break; } //Return our results. return result; } else if (OnNotificationOccured != null) OnNotificationOccured(packet, string.Format("Collection changed parser was called but the network id of '{0}' was not found in the registered objects.", data[0])); } else if (OnNotificationOccured != null) OnNotificationOccured(packet, "Collection changed packet was not in a correct format. Acepting a message in format of 'name:newstartindex:oldstartindex:value'"); //If we ever get here it means we encountered an error. We therefore return a null value. return null; }
public void SendPacket(NetworkPacket packet, object target) { byte[] packetRaw = new byte[_buffer.Length]; byte[] messageRaw = Encoding.UTF8.GetBytes(packet.Message); try { lock (_connection) { using (Stream m = new MemoryStream(packetRaw)) { for (int i = 0; i < (messageRaw.Length / _maxPacketLength); i++) { m.Position = 0; m.Write(BitConverter.GetBytes(_maxPacketLength + sizeof(Int32) + HeaderCollection.HeaderLength).Reverse().ToArray(), 0, sizeof(Int32)); m.Write(BitConverter.GetBytes((int)CorePacketCode.LongData).Reverse().ToArray(), 0, sizeof(Int32)); m.Write(packet.Header.ConvertToRawHeader(), 0, HeaderCollection.HeaderLength); m.Write(messageRaw, _maxPacketLength * i, _maxPacketLength); m.Flush(); SendRawPacket(target, packetRaw); System.Threading.Thread.Sleep(10); } m.Position = 0; m.Write(BitConverter.GetBytes(messageRaw.Length % _maxPacketLength + sizeof(Int32) + HeaderCollection.HeaderLength).Reverse().ToArray(), 0, sizeof(Int32)); m.Write(BitConverter.GetBytes(packet.Id).Reverse().ToArray(), 0, sizeof(Int32)); m.Write(packet.Header.ConvertToRawHeader(), 0, HeaderCollection.HeaderLength); m.Write(messageRaw, _maxPacketLength * (messageRaw.Length / _maxPacketLength), (messageRaw.Length % _maxPacketLength)); m.Flush(); SendRawPacket(target, packetRaw); } } } catch (Exception error) { ThrowException(error); } }
public PacketParsingWarning(string message, NetworkPacket packet) : this(message, packet, null) { }
protected abstract void SendPacket(NetworkPacket packet, params object[] excludeList);
protected abstract void SendSinglePacket(NetworkPacket packet, object target);
private void PropertyUpdated(NetworkPacket packet, NetworkEventArgs args) { SendPacket(packet, packet.Source); }
/// <summary> /// Send a specific network packet specified over the network. /// </summary> /// <param name="code">The packet to send over the network.</param> /// <param name="sendItself">Also send the object to itself.</param> public void SendEvent(NetworkPacket packet, bool sendItself, params object[] excludeList) { SendPacket(packet, excludeList); if (sendItself) ExecuteRegisteredEvents(packet); }
/// <summary> /// Event callback method to handle when a new client has been connected. /// </summary> /// <param name="packet">The source network packet.</param> /// <param name="args">The NetworkEventArgs containing all the data of the packet.</param> private void ClientConnected(NetworkPacket packet, NetworkEventArgs args) { //Check to see if the version of the network library matches. if (args.BasePacket.Header.GetValue<int>("ver") != this._header.GetValue<int>("ver")) { //The client is using a different version. We therefore disconnect him. Disconnect(args.SourceConnection); //Set handled to true so other events don't get called. args.Handled = true; } else _clientConnections.Add(args.SourceConnection); }
/// <summary> /// Send a packet over the network to a single client. Used only by the host. /// </summary> /// <param name="packet">The source packet to transmit over.</param> /// <param name="excludeList">A list of all the clients who will not recieve the packet. Only used for the host.</param> protected override void SendSinglePacket(NetworkPacket packet, object target) { _networkConnection.SendPacket(new NetworkPacket(packet.Id, packet.Message, null), target); }
/// <summary> /// Send a packet over the network. /// </summary> /// <param name="packet">The source packet to transmit over.</param> /// <param name="excludeList">A list of all the clients who will not recieve the packet.</param> protected override void SendPacket(NetworkPacket packet, params object[] excludeList) { for (int i = 0; i < _clientConnections.Count; i++) { bool skip = false; for (int exclude = 0; exclude < excludeList.Length; exclude++) if (_clientConnections[i] == excludeList[exclude]) { skip = true; break; } if (!skip) _networkConnection.SendPacket(packet, _clientConnections[i]); } }
/// <summary> /// Event called when any client or host connection has had any of its registered network data changed property. /// </summary> /// <param name="packet">The base packet containing the raw data.</param> /// <param name="data">NetworkEvent data containing the contents of the NetworkPacket in a parsed format.</param> /// <exception cref="NetworkLibrary.Exceptions.ParsingException" /> /// <exception cref="System.Exception" /> private void ConnectionPropertyChanged(NetworkPacket packet, NetworkEventArgs data) { try { //Check to see if the property changed packet we recieved was found in the registered objects collection. if (_registeredObjects.ContainsKey(data.NetworkDataId) && data.PropertyName != "Count") { try { //Disable listening on the object while we pass in the value. //This is done so that it doesn't end in an infinite loop between the host and the client. this.ListenerDisable(_registeredObjects[data.NetworkDataId]); //Set the value of the property on the object _registeredObjects[data.NetworkDataId].GetType().GetProperty(data.PropertyName).SetValue(_registeredObjects[data.NetworkDataId], data.Data, null); this.ListenerEnable(_registeredObjects[data.NetworkDataId]); } catch (Exception e) { throw new ParsingException(string.Format("Error while passing the value '{0}' of type '{1}' to the following property '{2}' on an object of type '{3}'. Error message received: {4}", data.Data, data.DataType.FullName, data.PropertyName, _registeredObjects[data.NetworkDataId].GetType().FullName, e.Message)); } } } catch (Exception e) { ThrowException(this, e); } }
/// <summary> /// Event callback to handle a new value assignment for the header. /// </summary> /// <param name="packet">The source network packet.</param> /// <param name="data">NetworkEventArgs containing all relevant data.</param> private void AssignValueInHeader(NetworkPacket packet, NetworkEventArgs data) { if (data.DataType == typeof(Header)) this._header.Add(data.Data as Header); }
protected void OnDataReceive(IAsyncResult data) { Socket s = data.AsyncState as Socket; try { s.EndReceive(data); } catch (ObjectDisposedException) { //After a close has been called, beginreceive will receive it's last call //This is done to do all necessary cleanup. When this happens, a ObjectDisposedException //will be thrown by the EndReceive and we will ignore this since it's none of our business :) return; } catch (Exception error) { if (OnNotificationOccured != null) OnNotificationOccured(s, "Error while receaving data, message received: " + error.Message); if (s.Connected) s.Close(); if (OnDisconnected != null) OnDisconnected(s, error); return; } int length = 0, codePacket = 0; string message = ""; HeaderCollection h; try { byte[] reverse = _buffer.Reverse().ToArray(); length = BitConverter.ToInt32(reverse, _buffer.Length - sizeof(Int32) - 0); if (length == 0) { if (OnNotificationOccured != null) OnNotificationOccured(_buffer, "An empty network packet was received and truncated."); } codePacket = BitConverter.ToInt32(reverse, _buffer.Length - sizeof(Int32) - 4); h = HeaderCollection.ConvertByteToCollection(_buffer, sizeof(int) * 2); char[] buffer = new char[_buffer.Length - 8 - HeaderCollection.HeaderLength + 1]; int temp = Encoding.UTF8.GetDecoder().GetChars(_buffer, 8 + HeaderCollection.HeaderLength, length - sizeof(Int32) - HeaderCollection.HeaderLength, buffer, 0); message = new string(buffer, 0, temp); } catch (Exception e) { if (OnNotificationOccured != null) OnNotificationOccured(this, "A network packet of an unknown format was recieved and truncated. While formatting the following error occured: " + e.Message); OpenConnection(s); return; } if (!OpenConnection(s)) return; NetworkPacket packet = new NetworkPacket(codePacket, message, s); packet.Header = h; if (packet.Id == (int)CorePacketCode.LongData) _longPackets.Add(packet); else if (OnPacketRecieved != null) { for (int i = _longPackets.Count - 1; i >= 0 ; i--) if (_longPackets[i].Source == packet.Source) { packet.Message = _longPackets[i].Message + packet.Message; _longPackets.Remove(_longPackets[i]); } OnPacketRecieved(this, packet); } }
/// <summary> /// Execute all registerd events for a specific packet code. /// </summary> /// <param name="packet">The source packet to send to the events.</param> private void ExecuteRegisteredEvents(NetworkPacket packet) { NetworkEventArgs args; if (_packetParsers.ContainsKey(packet.Id)) { args = _packetParsers[packet.Id].ParsePacket(packet); if (args == null) return; } else { args = new NetworkEventArgs(packet); if (packet.Message != null) { try { args.Data = new Serialiser().Deserialise(packet.Message); } catch (Exception e) { ThrowOnExceptionOccured(packet, e); return; } } else args.Data = null; } ExecuteEventsWithId(args, (int)CorePacketCode.PreviewPacket); if (packet.Id == (int)CorePacketCode.PropertyUpdated) ExecuteEventsWithId(args, (int)CorePacketCode.PreviewPropertyUpdated); if (packet.Id == (int)CorePacketCode.CollectionChanged) ExecuteEventsWithId(args, (int)CorePacketCode.PreviewCollectionChanged); ExecuteEventsWithId(args, packet.Id); }
/// <summary> /// Initialise a new instance of NetworkEvent with specified parameters. /// </summary> /// <param name="packet">The original packet raw.</param> public NetworkEventArgs(NetworkPacket packet) { _handled = false; _packet = packet; }
void ThrowOnPacketRecieved(object source, NetworkPacket packet) { ExecuteRegisteredEvents(packet); }
public PacketParsingWarning(string message, NetworkPacket packet, Exception e) : base(message, e) { _packet = packet; }
/// <summary> /// Parse an incoming string from an incoming packet and return a specialised NetworkEventArgs containg property changed information. /// </summary> /// <param name="item">The packet to parse.</param> /// <returns>Specialised NetworkEventArgs.</returns> public NetworkEventArgs ParsePacket(NetworkPacket packet) { //Split the message into maximum 3 parts because of the property changed packet format: //networkid:property_name:value string[] data = packet.Message.Split(new char[] { ':' }, 3); //Create the holder for our results. NetworkEventArgs result = new NetworkEventArgs(packet); //Make sure the message was correct. if (data.Length == 3) { INetworkDataHandler dataHandler = ObjectFactory.GetInstance<INetworkDataHandler>(); //Check to see if we have the object that had it's property changed. if (dataHandler.RegisteredObjects.ContainsKey(data[0])) { //We have the object so now we extract the information we want from the packet. result.NetworkDataId = data[0]; result.PropertyName = data[1]; try { //Deserialise the property value. result.Data = new Serialiser().Deserialise(data[2]); //Return our results. return result; } catch (Exception e) { //We received a valid packet but encountered an error while deserialising. //We pass this on as a warning. if (OnWarningOccured != null) OnWarningOccured(packet, new Warning(string.Format("Error while deserialising a property changed packet. Error message received: {0}.", e.Message), e)); } } else if (OnNotificationOccured != null) OnNotificationOccured(packet, string.Format("Error while processing an incoming property changed packet. Network object name of '{0}' was not found in the collection", data[0])); } else if (OnNotificationOccured != null) OnNotificationOccured(packet, "Property updated was not in a correct format. Acepting a message in format of 'name:property:value'"); //If we ever get here it means we encountered an error. We therefore return a null value. return null; }
/// <summary> /// Send a packet over the network to a single client. Used only by the host. /// </summary> /// <param name="packet">The source packet to transmit over.</param> /// <param name="excludeList">A list of all the clients who will not recieve the packet. Only used for the host.</param> protected override void SendSinglePacket(NetworkPacket packet, object target) { SendPacket(packet); }
public PacketParsingException(string message, NetworkPacket packet) : this(message, packet, null) { }