示例#1
0
        ///////////////////////////////////////////////////////////////////////////
        /**
         * Standard constructor
         */
        public RemoteConnection( Int32 ConnectionHandle,
								 AgentInfo NewRemoteAgentInfo,
								 RemoteConnectionInterfaceWrapper NewRemoteInterface )
            : base(ConnectionHandle)
        {
            Info = NewRemoteAgentInfo;
            Interface = NewRemoteInterface;
        }
示例#2
0
        /**
         * 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;
        }
示例#3
0
        /**
         * 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;
        }