public static void WriteHeader(this WBitStream bitStream, RemoteConnection remoteConnection, uint packetCode) { bitStream.Write((byte) 83); bitStream.Write((ushort) remoteConnection); bitStream.Write(packetCode); bitStream.Write((byte) 0); }
public static RemoteConnection CreateConnection(uint timeout) { RemoteConnection socket; if (connectionStorage.Count > 0) socket = connectionStorage.Dequeue(); else socket = new RemoteConnection(); socket.Connect(endpoint, port); return socket; }
/** * Used by an agent to open a remote connection to another agent. Remote * connections are bi-directional and this routine, along with its pair, * ConfirmRemoteConnection, are used to resolve all handshaking. Remote * connections are used by Agents to work on Tasks for Jobs they're * managing on behalf of a LocalConnection. */ public Int32 OpenRemoteConnection( string RequestingAgentName, Int32 ConnectionHandle, ELogFlags LoggingFlags, bool IsAssigned, DateTime AssignedTimestamp ) { // Always wait until the agent is fully initialized Initialized.WaitOne(); Int32 RemoteConnectionHandle = Constants.INVALID; CreateTimings( LoggingFlags ); StartTiming( "OpenRemoteConn-Internal", true ); // Make sure we only have one thread in here at a time lock( Connections ) { // Reject any incoming remote connection if: // we're in standalone mode // of if the CPU is already busy // or if a restart/exit has been requested if( ( AgentApplication.Options.EnableStandaloneMode ) || ( CurrentState == AgentState.Busy ) || ( AgentIsShuttingDown ) ) { return Constants.INVALID; } else { // Determine if this is a request for a connection or an assignment if( IsAssigned ) { // Make sure the assignment isn't stale if( AssignedTimestamp <= LastAssignedTime ) { return Constants.INVALID; } if( Connections.Count != 0 ) { // If there are any active jobs running in which the owner is the instigator, // meaning that this agent is connected directly to the instigator, reject foreach( AgentJob Job in ActiveJobs.Values ) { if( Job.OwnerIsInstigator ) { return Constants.INVALID; } } // Close any existing remote connections in favor of this incoming one foreach( Connection ExistingConnection in Connections.Values ) { if( ExistingConnection is RemoteConnection ) { Log( EVerbosityLevel.Informative, ELogColour.Orange, "[Connection] Detected incoming assigned remote connection, closing existing remote connection" ); Hashtable OldInParameters = null; Hashtable OldOutParameters = null; CloseConnection( ExistingConnection.Handle, OldInParameters, ref OldOutParameters ); } } } } else { // For connection requests, any other connection at all will cause a rejection if( Connections.Count != 0 ) { return Constants.INVALID; } } } // First, ping the remote host to make sure we can talk to it, // starting with verifying the Agent with the Coordinator try { if( ( Coordinator != null ) && ( CoordinatorResponding ) && ( AgentApplication.Options.EnableStandaloneMode == false ) ) { AgentInfo RequestingAgentInfo = null; Hashtable RequestedConfiguration = new Hashtable(); RequestedConfiguration["Version"] = new Version( 0, 0, 0, 0 ); RequestedConfiguration["RequestingAgentName"] = Environment.MachineName; List<AgentInfo> PotentialRemoteAgents = Coordinator.GetAvailableAgents( RequestedConfiguration ); foreach( AgentInfo NextAgentInfo in PotentialRemoteAgents ) { if( NextAgentInfo.Name == RequestingAgentName ) { RequestingAgentInfo = NextAgentInfo; break; } } if( RequestingAgentInfo != null ) { Debug.Assert( RequestingAgentInfo.Configuration.ContainsKey( "IPAddress" ) ); string RequestingAgentIPAddress = RequestingAgentInfo.Configuration["IPAddress"].ToString(); ValidateHostName(RequestingAgentIPAddress); // Now, ping the Agent if( PingRemoteHost( RequestingAgentName, RequestingAgentIPAddress ) ) { // Get the remote agent's interface object and wrap it string RemoteAgentURL = String.Format( "tcp://{0}:{1}/SwarmAgent", RequestingAgentIPAddress, Properties.Settings.Default.AgentRemotingPort.ToString() ); Agent RequestingAgentInterface = ( Agent )Activator.GetObject( typeof( Agent ), RemoteAgentURL ); RemoteConnectionInterfaceWrapper WrappedRequestingAgentInterface = new RemoteConnectionInterfaceWrapper( ConnectionHandle, RequestingAgentName, RequestingAgentIPAddress, RequestingAgentInterface ); Log( EVerbosityLevel.Informative, ELogColour.Green, "[Connect] Remote agent connection object obtained: " + RequestingAgentName ); // Confirm the connection try { // Send the connection GUID back to the requesting agent as // confirmation that we've received the request and plan to // accept it after the handshaking is complete RemoteConnectionHandle = WrappedRequestingAgentInterface.ConfirmRemoteConnection( ConnectionHandle ); if( RemoteConnectionHandle >= 0 ) { // Create the new remote connection object RemoteConnection NewRemoteConnection = new RemoteConnection( ConnectionHandle, RequestingAgentInfo, WrappedRequestingAgentInterface ); // There are times we want to ensure no new connections are coming online // where we'll lock the Connections dictionary (see MaintainCache). Note // that we're already in the lock above... Connections.Add( ConnectionHandle, NewRemoteConnection ); NewRemoteConnection.CurrentState = ConnectionState.CONNECTED; // Update our state and ping the coordinator CurrentState = AgentState.Working; WorkingFor = RequestingAgentName; if( IsAssigned ) { // Successful assignment LastAssignedTime = AssignedTimestamp; } PingCoordinator( true ); Log( EVerbosityLevel.Informative, ELogColour.Green, "[Connect] Remote agent connection confirmed: " + RequestingAgentName ); } } catch( Exception Ex ) { Log( EVerbosityLevel.Informative, ELogColour.Red, "[Connect] OpenRemoteConnection: " + Ex.ToString() ); RemoteConnectionHandle = Constants.ERROR_EXCEPTION; } } else { // Failed to ping, simply return with an appropriate error code Log( EVerbosityLevel.Informative, ELogColour.Red, "[Connect] Failed to ping " + RequestingAgentName + " at " + RequestingAgentIPAddress + " to confirm the remote connection" ); RemoteConnectionHandle = Constants.ERROR_CONNECTION_NOT_FOUND; } } else { // Failed to find the Agent info for the requesting Agent, simply return with an appropriate error code Log( EVerbosityLevel.Informative, ELogColour.Red, "[Connect] Failed to lookup " + RequestingAgentName + " in the Coordinator" ); RemoteConnectionHandle = Constants.ERROR_CONNECTION_NOT_FOUND; } } else { // Could not contact the Coordinator, simply return with an appropriate error code Log( EVerbosityLevel.Informative, ELogColour.Red, "[Connect] Failed to contact the Coordinator" ); RemoteConnectionHandle = Constants.ERROR_CONNECTION_NOT_FOUND; } } catch( Exception Ex ) { Log( EVerbosityLevel.Verbose, ELogColour.Red, "[Connect] Remote agent connection failed: " + RequestingAgentName ); Log( EVerbosityLevel.Verbose, ELogColour.Red, "[Connect] Exception details: " + Ex.ToString() ); } if( RemoteConnectionHandle < 0 ) { // If we get here, we have failed to create the connection Log( EVerbosityLevel.Informative, ELogColour.Red, "[Connect] Remote agent connection failed: " + RequestingAgentName ); } StopTiming(); } return RemoteConnectionHandle; }
/** * Used internally to try to open connections to remote agents */ public Int32 TryOpenRemoteConnection( LocalConnection ParentConnection, AgentInfo RemoteAgentInfo, bool IsAssigned, DateTime AssignedTimestamp, out RemoteConnection OpenedRemoteConnection ) { // Initialize the return values Int32 ErrorCode = Constants.INVALID; OpenedRemoteConnection = null; string RemoteAgentName = RemoteAgentInfo.Name; string RemoteAgentIPAddress = RemoteAgentInfo.Configuration["IPAddress"].ToString(); Log( EVerbosityLevel.Verbose, ELogColour.Green, "[Connect] Trying to open a remote connection to " + RemoteAgentName + " at " + RemoteAgentIPAddress ); bool bHostNameValid = true; try { ValidateHostName(RemoteAgentIPAddress); } catch (Exception) { ErrorCode = Constants.ERROR_EXCEPTION; bHostNameValid = false; } // First, ping the remote host to make sure we can talk to it if (bHostNameValid && PingRemoteHost(RemoteAgentName, RemoteAgentIPAddress)) { // Get the new unique handle that this connection will be known by Int32 NewConnectionHandle = GetUniqueHandle(); // Get the remote Agent interface object string RemoteAgentURL = String.Format( "tcp://{0}:{1}/SwarmAgent", RemoteAgentIPAddress, Properties.Settings.Default.AgentRemotingPort.ToString() ); Agent RemoteAgentInterface = ( Agent )Activator.GetObject( typeof( Agent ), RemoteAgentURL ); RemoteConnectionInterfaceWrapper WrappedRemoteAgentInterface = new RemoteConnectionInterfaceWrapper( NewConnectionHandle, RemoteAgentName, RemoteAgentIPAddress, RemoteAgentInterface ); Log( EVerbosityLevel.Verbose, ELogColour.Green, "[Connect] Remote agent interface object obtained for " + RemoteAgentName + " at " + RemoteAgentIPAddress ); // With the interface in hand, try to open a bi-directional connection. // Create the new RemoteConnection object and add it to the set // of pending connections, waiting for the incoming confirmation // which will move it to the active connection set. See // ConfirmRemoteConnection for where this happens. RemoteConnection NewRemoteConnection = new RemoteConnection( NewConnectionHandle, RemoteAgentInfo, WrappedRemoteAgentInterface ); PendingConnections.Add( NewConnectionHandle, NewRemoteConnection ); // Try to open the connection try { // Send the connection handle and the machine name that will // be used to construct the return URL for bi-directional // connection if( WrappedRemoteAgentInterface.OpenRemoteConnection( Environment.MachineName, NewConnectionHandle, LoggingFlags, IsAssigned, AssignedTimestamp ) >= 0 ) { // Successful confirmation, double check that the connection has moved if( PendingConnections.ContainsKey( NewConnectionHandle ) == false ) { if( Connections.ContainsKey( NewConnectionHandle ) ) { // Connection was successfully moved to the active connection set // thus the bi-directional communication link is established Log( EVerbosityLevel.Informative, ELogColour.Green, "[Connect] Successfully opened a remote connection with " + RemoteAgentName ); // Establish the parent-child relationship NewRemoteConnection.Parent = ParentConnection; NewRemoteConnection.Job = ParentConnection.Job; ParentConnection.RemoteChildren.Add( NewConnectionHandle, NewRemoteConnection ); ParentConnection.RemoteChildrenSeen++; ParentConnection.ChildrenSeen++; // Update the visualizer indicating that another remote connection is online if( NewRemoteConnection.Job.OwnerIsInstigator ) { AgentApplication.UpdateMachineState( RemoteAgentName, -1, EProgressionState.RemoteConnected ); } // Return the new handle for this connection OpenedRemoteConnection = NewRemoteConnection; ErrorCode = Constants.SUCCESS; } else { // Woah. Bad news. } } } else { // The connection failed to open, but didn't timeout and die, so it's likely just busy. // Return with a success code, but with no remote agent, signaling that it's possible // to try this one again later. ErrorCode = Constants.SUCCESS; } } catch( Exception Ex ) { Log( EVerbosityLevel.Verbose, ELogColour.Red, "[Connect] Exception: " + RemoteAgentName + ": " + Ex.ToString() ); ErrorCode = Constants.ERROR_EXCEPTION; } if( ErrorCode < 0 ) { Log( EVerbosityLevel.Verbose, ELogColour.Red, "[Connect] Failed to open a remote connection with " + RemoteAgentName ); } // Regardless of how we got here, make sure the connection has been removed // from the pending set (this is a safe call to make anytime) PendingConnections.Remove( NewConnectionHandle ); } else { // Failed to ping, simply return with an appropriate error code ErrorCode = Constants.ERROR_CONNECTION_NOT_FOUND; } return ErrorCode; }
public void Open() { // connect to one of our specified hosts baseStream = new RemoteConnection(); baseStream.Connect(MySqlConnection.CurrentStringBuilder.ServerEndPoint, MySqlConnection.CurrentStringBuilder.ServerPort); int maxSinglePacket = 255 * 255 * 255; stream = new MySqlStream(baseStream, Encoding, false); stream.ResetTimeout((int)Settings.ConnectionTimeout * 1000); // read off the welcome packet and parse out it's values packet = stream.ReadPacket(); int protocol = packet.ReadByte(); string versionString = packet.ReadString(); version = DBVersion.Parse(versionString); if (!version.isAtLeast(5, 0, 0)) throw new NotSupportedException(Resources.ServerTooOld); threadId = packet.ReadInteger(4); encryptionSeed = packet.ReadString(); maxSinglePacket = (256 * 256 * 256) - 1; // read in Server capabilities if they are provided ClientFlags serverCaps = 0; if (packet.HasMoreData) serverCaps = (ClientFlags)packet.ReadInteger(2); /* New protocol with 16 bytes to describe server characteristics */ owner.ConnectionCharSetIndex = (int)packet.ReadByte(); serverStatus = (ServerStatusFlags)packet.ReadInteger(2); // Since 5.5, high bits of server caps are stored after status. // Previously, it was part of reserved always 0x00 13-byte filler. uint serverCapsHigh = (uint)packet.ReadInteger(2); serverCaps |= (ClientFlags)(serverCapsHigh << 16); packet.Position += 11; string seedPart2 = packet.ReadString(); encryptionSeed += seedPart2; string authenticationMethod = ""; if ((serverCaps & ClientFlags.PLUGIN_AUTH) != 0) { authenticationMethod = packet.ReadString(); } else { // Some MySql versions like 5.1, don't give name of plugin, default to native password. authenticationMethod = "mysql_native_password"; } // based on our settings, set our connection flags SetConnectionFlags(serverCaps); packet.Clear(); packet.WriteInteger((int)connectionFlags, 4); packet.WriteInteger(maxSinglePacket, 4); packet.WriteByte(8); packet.Write(new byte[23]); Authenticate(authenticationMethod, false); // if we are using compression, then we use our CompressedStream class // to hide the ugliness of managing the compression if ((connectionFlags & ClientFlags.COMPRESS) != 0) stream = new MySqlStream(baseStream, Encoding, true); // give our stream the server version we are connected to. // We may have some fields that are read differently based // on the version of the server we are connected to. packet.Version = version; stream.MaxBlockSize = maxSinglePacket; }
private void ExecuteInsertGameData(DbGame game) { game.IsSynchronised = true; LocalConnection.Update(game); Guid gameId = game.Id; List <DbAttackGoal> goals = new List <DbAttackGoal>(); List <DbAttack> attacks = new List <DbAttack>(); List <DbAttackRebound> rebounds = new List <DbAttackRebound>(); List <DbAttackShot> shots = new List <DbAttackShot>(); MySqlCommand remoteCommand = new MySqlCommand(); MySqlTransaction transaction = RemoteConnection.BeginTransaction(); remoteCommand.Transaction = transaction; try { var localAttacks = LocalConnection; string query = "SELECT * FROM Attack WHERE GameId = ?"; SQLiteCommand command = LocalConnection.CreateCommand(query, gameId); attacks = command.ExecuteQuery <DbAttack>(); string getGoalsQuery = "SELECT ag.* FROM Attack a" + " JOIN AttackGoal ag" + " on a.GoalId = ag.Id" + " WHERE a.GameId = ? AND a.IsSynchronised = 0"; command = LocalConnection.CreateCommand(getGoalsQuery, gameId); goals = command.ExecuteQuery <DbAttackGoal>(); string insertGoalsQuery = CreateInsertStatement(goals, "Attack_Goal"); string insertAttacksQuery = CreateInsertStatement(attacks, "Attack"); string localShotsQuery = "SELECT ash.* FROM Attack a" + " join AttackShot ash" + " on a.Id = ash.AttackId" + " WHERE a.GameId = ? AND a.IsSynchronised = 0"; command = LocalConnection.CreateCommand(localShotsQuery, gameId); shots = command.ExecuteQuery <DbAttackShot>(); string insertShotsQuery = CreateInsertStatement(shots, "Attack_Shot"); string localReboundsQuery = "SELECT ash.* FROM Attack a" + " join AttackShot ash " + " on a.Id = ash.AttackId" + " WHERE a.GameId = ? AND a.IsSynchronised = 0"; command = LocalConnection.CreateCommand(localReboundsQuery, gameId); rebounds = command.ExecuteQuery <DbAttackRebound>(); string insertReboundsQuery = CreateInsertStatement(rebounds, "Attack_Rebound"); remoteCommand.Connection = RemoteConnection; remoteCommand.CommandText = insertGoalsQuery; remoteCommand.ExecuteNonQuery(); remoteCommand.CommandText = insertAttacksQuery; remoteCommand.ExecuteNonQuery(); remoteCommand.CommandText = insertReboundsQuery; remoteCommand.ExecuteNonQuery(); remoteCommand.CommandText = insertShotsQuery; remoteCommand.ExecuteNonQuery(); transaction.Commit(); goals.ForEach(g => g.IsSynchronised = true); attacks.ForEach(a => a.IsSynchronised = true); rebounds.ForEach(r => r.IsSynchronised = true); shots.ForEach(s => s.IsSynchronised = true); LocalConnection.UpdateAll(goals); LocalConnection.UpdateAll(attacks); LocalConnection.UpdateAll(rebounds); LocalConnection.UpdateAll(shots); } catch (Exception e) { transaction.Rollback(); throw new Exception(e.Message); } }
private void Initialize() { RemoteConnection.Establish(); CommunicationDirectory.WaitForServiceReady(DiscoveryServiceName, null, DefaultConnectionTimeout); }
public void InsertAttack(IAttack attack) { bool isGoal = attack.Goal != null; string attackGoalInsert = string.Empty; if (isGoal) { attackGoalInsert = CreateInsertStatement(attack.Goal, "Attack_Goal"); } bool insertShot = attack.Shots.Count > 0; string attackInsert = CreateInsertStatement(attack.DbAttack, "Attack"); string attackShotInsert = string.Empty; if (insertShot) { attackShotInsert = CreateInsertStatement(attack.Shots, "Attack_Shot"); } string attackReboundInsert = string.Empty; bool insertRebounds = attack.Rebounds.Count > 0; if (insertRebounds) { CreateInsertStatement(attack.Rebounds, "Attack_Rebound"); } MySqlCommand command = new MySqlCommand(); command.Connection = RemoteConnection; MySqlTransaction transaction = RemoteConnection.BeginTransaction(); command.Transaction = transaction; try { if (isGoal) { command.CommandText = attackGoalInsert; command.ExecuteNonQuery(); } command.CommandText = attackInsert; command.ExecuteNonQuery(); if (insertShot) { command.CommandText = attackShotInsert; command.ExecuteNonQuery(); } if (insertRebounds) { command.CommandText = attackReboundInsert; command.ExecuteNonQuery(); } transaction.Commit(); } catch (Exception e) { transaction.Rollback(); Console.WriteLine(e.Message); } }
private static void OnBeforeChildProcessLaunch(object sender, Chromium.Event.CfxOnBeforeChildProcessLaunchEventArgs e) { if(e.CommandLine.HasSwitch("type") && e.CommandLine.GetSwitchValue("type") == "renderer") { var pipeName = "cfx" + Guid.NewGuid().ToString().Replace("-", string.Empty); var pipeIn = PipeFactory.Instance.CreateServerPipeInputStream(pipeName + "si"); var pipeOut = PipeFactory.Instance.CreateServerPipeOutputStream(pipeName + "so"); var connection = new RemoteConnection(pipeIn, pipeOut, false); connections.Add(connection); e.CommandLine.AppendSwitchWithValue("cfxremote", pipeName); } }
/** * Actual work performed by SendMessage happens here */ public Int32 SendMessageInternal(Connection Sender, AgentMessage NewMessage) { Int32 ErrorCode = Constants.INVALID; // We assume the message is valid, but if somewhere below we change our // mind, this value will be set to false and we'll eat the message bool bMessageIsValid = true; // Logic for the setting of the To and From fields (if not already set) // // All connections sending messages are implicitly sending them to the // Instigator of the Job they're working on. Depending on where the // message is coming from, we might need to patch up the To field a // little bit to ensure it's heading to a Local connection when it // needs to be. The only case this applies is when we receive a message // from a Remote connection, directed toward a Remote connection, which // happens when we get a message from a Remote Agent from an even more // Remote connection (i.e. a Job connection on the remote machine): // // To Local, From Local -> routing of main message and replies are ok // To Local, From Remote -> routing of main message and replies are ok // To Remote, From Local -> routing of main message and replies are ok // To Remote, From Remote -> routing of replies is ok, but the main // message is in trouble if it's not completely handled within the // Agent's ProcessMessages routine. It would be forwarded on to the // To field connection which is Remote and we'd end up bouncing the // message back and forth forever. Need to adjust the To field to // point to the parent of the To connection (which is where it's // intended to go anyway). See further below for where we handle // this case. // If the From field is not set, give it the connection handle value by // default so that any response message will automatically be routed back // to it whether it's the sender or the recipient if (NewMessage.From == Constants.INVALID) { NewMessage.From = Sender.Handle; } // If the connection used to send the message is Remote, check for the // Remote -> Remote case described above else if (Sender is RemoteConnection) { // If the From field is already set, see if we've already registered // the connection this message is being sent from Connection FromConnection; if (!Connections.TryGetValue(NewMessage.From, out FromConnection)) { // This is a new one - make it an alias for the sender so that any // responses will be directed back via its sending interface RemoteConnection RemoteSender = Sender as RemoteConnection; RemoteSender.Aliases.Add(NewMessage.From); // There are times we want to ensure no new connections are coming online // where we'll lock the Connections dictionary (see MaintainCache) lock ( Connections ) { Connections.Add(NewMessage.From, RemoteSender); } FromConnection = RemoteSender; string LogMessage = String.Format("[SendMessage] Added alias for remote connection: {0:X8} is an alias for {1:X8}", NewMessage.From, Sender.Handle); Log(EVerbosityLevel.Informative, ELogColour.Green, LogMessage); } // If this is a Remote -> Remote situation, the proper place to route // the message to the parent of the remote connection since the Agents // generally act as glue between connections if (FromConnection is RemoteConnection) { Debug.Assert(NewMessage.To != Constants.INVALID); Connection ToConnection; if ((Connections.TryGetValue(NewMessage.To, out ToConnection)) && (ToConnection is RemoteConnection)) { Connection ToConnectionParent = ToConnection.Parent; if (ToConnectionParent != null) { NewMessage.To = ToConnectionParent.Handle; } } } } // If the To field is not set, assign it based on the message type if (NewMessage.To == Constants.INVALID) { // TODO: As we add additional versions, convert to a switch rather than if-else. // For now, just use a simple if since we only have one version and a switch is // overkill. if (NewMessage.Version == ESwarmVersionValue.VER_1_0) { // The default is for messages to be ultimately routed to the Instigator // unless the message is one of a certain set of types that route // directly to the connection specified switch (NewMessage.Type) { // These message types need to be routed to the connection specified // either because they are meant to be simple round-trip messages or // because they are sent from within Swarm directly to the connection // and should not be routed anywhere else case EMessageType.QUIT: case EMessageType.PING: case EMessageType.SIGNAL: NewMessage.To = Sender.Handle; break; // These message types need to be routed eventually to the Instigator // connection, which is the ultimate ancestor up the parent chain, so // simply assign the most senior parent we have case EMessageType.INFO: case EMessageType.ALERT: case EMessageType.TIMING: case EMessageType.TASK_REQUEST: case EMessageType.TASK_STATE: case EMessageType.JOB_STATE: // By default, make the sender the recipient for these cases, in // case the parent is no longer active NewMessage.To = Sender.Handle; Connection SenderParent = Sender.Parent; if (SenderParent != null) { // If we have a parent connection and it's active, then // assign it as the recipient if (SenderParent.CurrentState == ConnectionState.CONNECTED) { NewMessage.To = SenderParent.Handle; } } break; // These message types are not expected and are each error cases case EMessageType.NONE: // Should never be set to this case EMessageType.JOB_SPECIFICATION: // Only used for messages going directly into OpenJob case EMessageType.TASK_REQUEST_RESPONSE: // Should always have the To field set already default: Log(EVerbosityLevel.Informative,ELogColour.Orange,"SendMessage: Invalid message type received, ignoring " + NewMessage.Type.ToString()); break; } // If still no assigned To field, consider it an error if (NewMessage.To == Constants.INVALID) { Log(EVerbosityLevel.Informative, ELogColour.Orange, "SendMessage: No proper recipient found, ignoring " + NewMessage.Type.ToString()); bMessageIsValid = false; } } } // If the message remains valid, post it to the queue if (bMessageIsValid) { lock ( MessageQueueLock ) { Debug.Assert(NewMessage != null); MessageQueueSM.Enqueue(NewMessage); string NewLogMessage = String.Format("Step 1 of N for message: ({0:X8} -> {1:X8}), {2}, Message Count {3} (Agent)", NewMessage.To, NewMessage.From, NewMessage.Type, MessageQueueSM.Count); Log(EVerbosityLevel.SuperVerbose, ELogColour.Green, NewLogMessage); MessageQueueReady.Set(); } ErrorCode = Constants.SUCCESS; } else { Log(EVerbosityLevel.Informative, ELogColour.Orange, String.Format("SendMessage: Discarded message \"{0}\"", NewMessage.Type)); } return(ErrorCode); }
/** * Takes messages off the internal message queue and handles them by either * sending responses, forwarding the message on, or processing it internally */ private void ProcessMessagesThreadProc() { // A response message queue used to send messages back to the one which sent it Queue <AgentMessage> ResponseMessageQueue = new Queue <AgentMessage>(); while (AgentHasShutDown == false) { StartTiming("ProcessMessage-Internal", true); lock ( MessageQueueLock ) { // Swap the SM and PM message queue to keep things moving at full speed Queue <AgentMessage> Temp = MessageQueuePM; MessageQueuePM = MessageQueueSM; MessageQueueSM = Temp; } // Process all messages currently in the queue while (MessageQueuePM.Count > 0) { Debug.Assert(ResponseMessageQueue.Count == 0); // Get and process the next message AgentMessage NextMessage = MessageQueuePM.Dequeue(); Debug.Assert(NextMessage != null); bool bMessageHandled = false; switch (NextMessage.Type) { case EMessageType.SIGNAL: { if (NextMessage is DisconnectionSignalMessage) { // Mark the connection as inactive DisconnectionSignalMessage DisconnectMessage = NextMessage as DisconnectionSignalMessage; Log(EVerbosityLevel.Informative,ELogColour.Green,String.Format("[CloseConnection] Connection disconnected {0:X8}",DisconnectMessage.ConnectionToDisconnect.Handle)); DisconnectMessage.ConnectionToDisconnect.CurrentState = ConnectionState.DISCONNECTED; DisconnectMessage.ConnectionToDisconnect.DisconnectedTime = DateTime.UtcNow; } // Signal the message and move on AgentSignalMessage SignalMessage = NextMessage as AgentSignalMessage; SignalMessage.ResetEvent.Set(); bMessageHandled = true; } break; case EMessageType.TIMING: { Connection FromConnection; if ((Connections.TryGetValue(NextMessage.From,out FromConnection))) { Connection ToConnection; if ((Connections.TryGetValue(NextMessage.To,out ToConnection)) && (ToConnection is LocalConnection)) { // Handle message AgentTimingMessage TimingMessage = NextMessage as AgentTimingMessage; AgentApplication.UpdateMachineState(MachineNameFromConnection(FromConnection),TimingMessage.ThreadNum,TimingMessage.State); bMessageHandled = true; } } } break; case EMessageType.TASK_REQUEST: { // Look up the requesting connection Debug.Assert(NextMessage.From != Constants.INVALID); Connection RequestingConnection; if (Connections.TryGetValue(NextMessage.From,out RequestingConnection)) { // Look up the specified Job AgentJob JobToAskForTasks = RequestingConnection.Job; if (JobToAskForTasks != null) { // If we get a valid response back, add it to the queue AgentTaskRequestResponse Response = JobToAskForTasks.GetNextTask(RequestingConnection); if (Response != null) { ResponseMessageQueue.Enqueue(Response); // Specifications and releases are always handled here, but // reservations are special in that we will send a reservation // back to local connections but we'll need to make sure the // message continues on to remote connections. if ((Response.ResponseType == ETaskRequestResponseType.SPECIFICATION) || (Response.ResponseType == ETaskRequestResponseType.RELEASE) || ((Response.ResponseType == ETaskRequestResponseType.RESERVATION) && (JobToAskForTasks.Owner is LocalConnection))) { bMessageHandled = true; } } } else { // Unable to find the Job, just send back a release message Log(EVerbosityLevel.Verbose,ELogColour.Orange,"[ProcessMessage] Unable to find Job for Task Request; may have been closed"); //ResponseMessageQueue.Enqueue( new AgentTaskRequestResponse( RequestingConnection.Job.JobGuid, // ETaskRequestResponseType.RELEASE ) ); bMessageHandled = true; } } else { // Unable to find the connection, swallow the request Log(EVerbosityLevel.Verbose,ELogColour.Orange,"[ProcessMessage] Unable to find owning Connection for Task Request"); bMessageHandled = true; } } break; case EMessageType.TASK_STATE: { // Look up the sending connection Debug.Assert(NextMessage.From != Constants.INVALID); Connection SendingConnection; if ((Connections.TryGetValue(NextMessage.From,out SendingConnection)) && (SendingConnection.Job != null)) { // Look up the specified Job AgentJob UpdatedJob; if (ActiveJobs.TryGetValue(SendingConnection.Job.JobGuid,out UpdatedJob)) { AgentTaskState UpdatedTaskState = NextMessage as AgentTaskState; UpdatedJob.UpdateTaskState(UpdatedTaskState); if (UpdatedJob.Owner is LocalConnection) { // If the Task state change is of a type potentially interesting to // the Instigator, return it switch (UpdatedTaskState.TaskState) { case EJobTaskState.TASK_STATE_INVALID: case EJobTaskState.TASK_STATE_COMPLETE_SUCCESS: case EJobTaskState.TASK_STATE_COMPLETE_FAILURE: // For these message types, allow the message to continue on break; default: // Nothing to do otherwise, mark the message as handled bMessageHandled = true; break; } } else { // Always send messages on for remote connections } } else { // Unable to find the Job, swallow the request Log(EVerbosityLevel.Verbose,ELogColour.Orange,"[ProcessMessage] Unable to find Job for Task Request"); bMessageHandled = true; } } else { // Unable to find the connection, swallow the request Log(EVerbosityLevel.Verbose,ELogColour.Orange,"[ProcessMessage] Unable to find owning Connection for Task Request"); bMessageHandled = true; } } break; } // If the message was not handled completely, send it on if (bMessageHandled == false) { // Look up who the message is being sent to and make sure they're // still active and if not, ignore the message Connection Recipient; Debug.Assert(NextMessage.To != Constants.INVALID); if (Connections.TryGetValue(NextMessage.To,out Recipient)) { if (Recipient is LocalConnection) { // If the recipient is local, place it in the proper queue // and signal that a message is ready LocalConnection LocalRecipient = Recipient as LocalConnection; lock (LocalRecipient.MessageQueue) { LocalRecipient.MessageQueue.Enqueue(NextMessage); string NewLogMessage = String.Format("Step 2 of 4 for message: ({0:X8} -> {1:X8}), {2}, Message Count {3} (Local Connection)", NextMessage.To, NextMessage.From, NextMessage.Type, LocalRecipient.MessageQueue.Count); Log(EVerbosityLevel.SuperVerbose,ELogColour.Green,NewLogMessage); LocalRecipient.MessageAvailableSignal(); } } else { Debug.Assert(Recipient is RemoteConnection); // If the recipient is remote, send the message via SendMessage // unless the message is a Task being sent back, which is sent // via the dedicated Task API RemoteConnection RemoteRecipient = Recipient as RemoteConnection; if (NextMessage is AgentTaskSpecification) { // All new Tasks are sent via the dedicated Task API AgentTaskSpecification TaskSpecification = NextMessage as AgentTaskSpecification; Hashtable RemoteInParameters = new Hashtable(); RemoteInParameters["Version"] = ESwarmVersionValue.VER_1_0; RemoteInParameters["Specification"] = TaskSpecification; Hashtable RemoteOutParameters = null; Int32 Error = RemoteRecipient.Interface.AddTask(RemoteRecipient.Handle,RemoteInParameters,ref RemoteOutParameters); if (Error >= 0) { // Perhaps we should be sending an accept message back? } else { AgentTaskState UpdateMessage; if (Error == Constants.ERROR_CONNECTION_DISCONNECTED) { // Special case of the connection dropping while we're adding the // task, say it's been killed to requeue UpdateMessage = new AgentTaskState(TaskSpecification.JobGuid, TaskSpecification.TaskGuid, EJobTaskState.TASK_STATE_KILLED); } else { // All other error cases will be rejections UpdateMessage = new AgentTaskState(TaskSpecification.JobGuid, TaskSpecification.TaskGuid, EJobTaskState.TASK_STATE_REJECTED); } AgentJob Job; if (ActiveJobs.TryGetValue(TaskSpecification.JobGuid,out Job)) { Job.UpdateTaskState(UpdateMessage); } } } else { // All standard messages are sent via the SendMessage API Hashtable RemoteInParameters = new Hashtable(); RemoteInParameters["Version"] = ESwarmVersionValue.VER_1_0; RemoteInParameters["Message"] = NextMessage; Hashtable RemoteOutParameters = null; RemoteRecipient.Interface.SendMessage(NextMessage.To,RemoteInParameters,ref RemoteOutParameters); } string NewLogMessage = String.Format("Step 2 of 2 for message: ({0:X8} -> {1:X8}), {2}, (Remote Connection)", NextMessage.To, NextMessage.From, NextMessage.Type); Log(EVerbosityLevel.SuperVerbose,ELogColour.Green,NewLogMessage); } } else { Log(EVerbosityLevel.Informative,ELogColour.Orange,"ProcessMessage: Message sent to invalid connection, ignoring: " + NextMessage.Type.ToString()); } } // If there are any responses to the message, send them if (ResponseMessageQueue.Count > 0) { foreach (AgentMessage NextResponse in ResponseMessageQueue) { // For each one of the messages, set the routing fields properly NextResponse.To = NextMessage.From; NextResponse.From = NextMessage.To; // And then queue the message back up immediately MessageQueuePM.Enqueue(NextResponse); } ResponseMessageQueue.Clear(); } } StopTiming(); // Wait for a message to become available and once unlocked, swap the queues // and check for messages to process. Set a timeout, so we'll wake up every // now and then to check for a quit signal at least MessageQueueReady.WaitOne(500); } }
internal CfxRemoteCallContext(RemoteConnection connection, int threadId) { this.connection = connection; ThreadId = threadId; }
public MySqlStream(RemoteConnection baseStream, Encoding encoding, bool compress) : this(encoding) { this.connection = baseStream; }