internal object SendSyncedMessage(NetCoreAdvancedMessage message, bool priority = false) { //A synced will block the sender's thread until a response is received if (!IsSendingAdvancedMessageAuthorized(message)) { return(null); } message.requestGuid = Guid.NewGuid(); lock (PeerMessageQueueLock) { if (priority) { PeerMessageQueue.AddFirst(message); } else { PeerMessageQueue.AddLast(message); } } ConsoleEx.WriteLine($"{spec.Side.ToString()}:Sent synced advanced message \"{message.Type.ToString()}\", priority:{priority.ToString()}"); return(spec.Connector.watch.GetValue((Guid)message.requestGuid, message.Type)); //This will lock here until value is returned from peer }
public void AddReturn(NetCoreAdvancedMessage message) { if (!message.requestGuid.HasValue) { return; } SyncReturns.TryAdd(message.requestGuid.Value, message.objectValue); }
public void setReturnValue(object _objectValue) { var message = new NetCoreAdvancedMessage("{RETURNVALUE}") { objectValue = _objectValue }; if (returnMessage != null) { RTCV.Common.Logging.GlobalLogger.Warn($"NetCoreEventArgs: ReturnValue was already set but was overriden with another value"); } _returnMessage = message; }
internal bool IsSendingAdvancedMessageAuthorized(NetCoreAdvancedMessage message) { if (message.Type == "{HI}") // {HI} is the only command that can go blindly through the pipe before the link is established { return(true); } else if (status != NetworkStatus.CONNECTED) { ConsoleEx.WriteLine($"{spec.Side.ToString()} -> Can't send message \"{message.Type.ToString()}\", link is not established"); return(false); } return(true); }
public void setReturnValue(object _objectValue) { var message = new NetCoreAdvancedMessage("{RETURNVALUE}") { objectValue = _objectValue }; if (returnMessage != null) { ConsoleEx.WriteLine($"ReturnValue was already set but was overriden with another value"); } _returnMessage = message; }
internal void SendMessage(NetCoreAdvancedMessage message, bool priority = false) { if (!IsSendingAdvancedMessageAuthorized(message)) { return; } lock (PeerMessageQueueLock) { if (priority) //If there is a stream of data occuring, priority ensures that a message will skip the line and gets sent ASAP { PeerMessageQueue.AddFirst(message); } else { PeerMessageQueue.AddLast(message); } } ConsoleEx.WriteLine($"{spec.Side.ToString()} -> Sent advanced message \"{message.Type.ToString()}\", priority:{priority.ToString()}"); }
public NetCoreEventArgs(string type, object objectValue) { message = new NetCoreAdvancedMessage(type, objectValue); }
public void AddReturn(NetCoreAdvancedMessage message) { SyncReturns.Add((Guid)message.requestGuid, message.objectValue); }
internal bool ProcessAdvancedMessage(NetCoreMessage _message) { NetCoreAdvancedMessage message; if (_message is NetCoreAdvancedMessage) { message = (_message as NetCoreAdvancedMessage); } else { message = new NetCoreAdvancedMessage(_message.Type); // promote message to Advanced if simple ({BOOP} command goes through UDP Link) } if (!message.Type.StartsWith("{EVENT_") || ConsoleEx.ShowDebug) { ConsoleEx.WriteLine(spec.Side.ToString() + ":Process advanced message -> " + message.Type.ToString()); } switch (message.Type) { // NetCore Internal Commands // Some of these commands go through the UDP Link but are upgraded to an Advanced Message // As they are parsed by the Message Hub case "{HI}": //Greetings to confirm that communication is established expectingSomeone = true; status = NetworkStatus.CONNECTED; if (spec.Side == NetworkSide.SERVER) { //Server receives {HI} after client has established connection ConsoleEx.WriteLine($"TCP Server Connected"); //spec.OnServerConnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_SERVERCONNECTED}")); SendMessage(new NetCoreAdvancedMessage("{HI}")); } else //(side == NetworkSide.CLIENT) { //Client always sends the first {HI} but will wait for the Server to reply with one ConsoleEx.WriteLine($"TCP Client Connected to {IP}:{Port}"); //spec.OnClientConnected(null); spec.Connector.hub.QueueMessage(new NetCoreAdvancedMessage("{EVENT_CLIENTCONNECTED}")); } break; case "{BYE}": // End of disconnect Kill(); break; case "{BOOP}": // Ping system to confirm is TCP link is still in order // Boops are redirected through the UDP pipe so if the TCP Link is busy transfering a lot of data // or is jammed waiting for a return, these will still go through BoopMonitoringCounter = DefaultBoopMonitoringCounter; break; //THREADSAFE EVENT FIRING case "{EVENT_CLIENTCONNECTING}": spec.OnClientConnecting(null); break; case "{EVENT_CLIENTCONNECTINGFAILED}": spec.OnClientConnectingFailed(null); break; case "{EVENT_CLIENTCONNECTED}": spec.OnClientConnected(null); break; case "{EVENT_CLIENTDISCONNECTED}": spec.OnClientDisconnected(null); break; case "{EVENT_CLIENTCONNECTIONLOST}": spec.OnClientConnectionLost(null); break; case "{EVENT_SERVERLISTENING}": spec.OnServerListening(null); break; case "{EVENT_SERVERCONNECTED}": spec.OnServerConnected(null); break; case "{EVENT_SERVERDISCONNECTED}": spec.OnServerDisconnected(null); break; case "{EVENT_SERVERCONNECTIONLOST}": spec.OnServerConnectionLost(null); break; case "{EVENT_SYNCEDMESSAGESTART}": spec.OnSyncedMessageStart(null); break; case "{EVENT_SYNCEDMESSAGEEND}": spec.OnSyncedMessageEnd(null); break; default: //If message wasn't procesed, just return false //Message may be handled on an upper level return(false); } return(true); }
private void StoreMessages(NetworkStream providedStream) { var config = new SerializerConfig(); config.Advanced.PersistTypeCache = true; config.OnResolveFormatter.Add((c, t) => { if (t == typeof(HashSet <byte[]>)) { return(new NetCore.NetCore_Extensions.HashSetFormatterThatKeepsItsComparer()); } return(null); // continue searching }); var serializer = new CerasSerializer(config); TcpListener server = null; Socket socket = null; NetworkStream networkStream = null; if (providedStream != null) { networkStream = providedStream; } try { if (networkStream == null) { server = new TcpListener((IP == "127.0.0.1" ? IPAddress.Loopback : IPAddress.Any), Port); server.Start(); socket = KillableAcceptSocket(server); networkStream = new NetworkStream(socket); server.Stop(); } networkStream.ReadTimeout = 20; networkStream.WriteTimeout = int.MaxValue; //Using {BOOP} commands routed through UDP/TCP if (spec.Side == NetworkSide.CLIENT) { SendMessage(new NetCoreAdvancedMessage("{HI}")); //The exchange of {HI} command confirms that link is established on Receiving } while (true) { if (networkStream != null && networkStream.DataAvailable) { if (spec.Side == NetworkSide.SERVER && (!socket?.Connected ?? true)) { return; } NetCoreAdvancedMessage message = null; try { using (MemoryStream ms = new MemoryStream()) { Stopwatch sw = new Stopwatch(); sw.Start(); //Read the size int lengthToReceive = 0; byte[] _lengthToReceive = new byte[4]; networkStream.Read(_lengthToReceive, 0, _lengthToReceive.Length); lengthToReceive = BitConverter.ToInt32(_lengthToReceive, 0); //Console.WriteLine("I want this many bytes: " + lengthToReceive); //Now read until we have that many bytes long bytesRead = CopyBytes(lengthToReceive, networkStream, ms); //Console.WriteLine("I got this many bytes: " + bytesRead); //Deserialize it ms.Position = 0; //cmd = (RTC_Command)binaryFormatter.Deserialize(ms); var temp = ms.ToArray(); message = serializer.Deserialize <NetCoreAdvancedMessage>(temp); sw.Stop(); if (message.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50) { Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to deserialize cmd " + message.Type + " of " + temp.Length + " bytes"); } } } catch { throw; } if (message != null) { if (message.Type == "{RETURNVALUE}") { spec.Connector.watch.AddReturn(message); } else { spec.Connector.hub.QueueMessage(message); } } } while (PeerMessageQueue.Count > 0) { NetCoreMessage pendingMessage; lock (PeerMessageQueueLock) { pendingMessage = PeerMessageQueue.First.Value; PeerMessageQueue.RemoveFirst(); } try { Stopwatch sw = new Stopwatch(); sw.Start(); //Write the length of the command to the first four bytes byte[] buf = serializer.Serialize(pendingMessage); //Write the length of the incoming object to the NetworkStream byte[] length = BitConverter.GetBytes(buf.Length); networkStream.Write(length, 0, length.Length); networkStream.Write(buf, 0, buf.Length); sw.Stop(); if (pendingMessage.Type != "{BOOP}" && sw.ElapsedMilliseconds > 50) { Console.WriteLine("It took " + sw.ElapsedMilliseconds + " ms to serialize backCmd " + pendingMessage.Type + " of " + buf.Length + " bytes"); } } catch { throw; } if (pendingMessage.Type == "{BYE}") { lock (PeerMessageQueueLock) //Since we're shutting down, let's clear the message queue PeerMessageQueue?.Clear(); } if (status == NetworkStatus.DISCONNECTED || status == NetworkStatus.CONNECTIONLOST) { //If the link's status changed from an outside factor, we want to stop the thread. lock (PeerMessageQueueLock) PeerMessageQueue?.Clear(); return; } } Thread.Sleep(spec.messageReadTimerDelay); } } catch (Exception ex) { if (ex is ThreadAbortException) { ConsoleEx.WriteLine("Ongoing TCPLink Thread Killed"); } else if (ex.InnerException != null && ex.InnerException is SocketException) { ConsoleEx.WriteLine("Ongoing TCPLink Socket Closed during use"); } else if (ex is SerializationException) { ConsoleEx.WriteLine("Ongoing TCPLink Closed during Serialization operation"); } else if (ex is ObjectDisposedException) { ConsoleEx.WriteLine("Ongoing TCPLink Closed during Socket acceptance"); } else { DiscardException(ex); } } finally { //Let's force close everything JUST IN CASE try { networkStream?.Close(); networkStream?.Dispose(); } catch { } //nobody cares why this failed try { socket?.Shutdown(SocketShutdown.Both); socket?.Dispose(); } catch { } //nobody cares why this failed try { server?.Stop(); } catch (Exception ex) { DiscardException(ex); } if (status == NetworkStatus.CONNECTED) { status = (expectingSomeone ? NetworkStatus.CONNECTIONLOST : NetworkStatus.DISCONNECTED); } else if (status != NetworkStatus.CONNECTIONLOST) { status = NetworkStatus.DISCONNECTED; } //Kill synced query if happenning spec.Connector.watch.Kill(); } }