public Int32 OpenJob( Connection NewOwner, AgentGuid NewJobGuid ) { // Create the bi-directional link between the job and its owner NewOwner.Job = this; Owner = NewOwner; // Determine if the owner is the Instigator, and if so, perform // any additional work necessary if( NewOwner is LocalConnection ) { OwnerIsInstigator = true; // If the owner of the job is the Instigator, set the current working // directory to be where the Instigator process is executing LocalConnection LocalNewOwner = NewOwner as LocalConnection; Manager.SetCurrentDirectoryByProcessID( LocalNewOwner.ProcessID ); // Update the visualizer AgentApplication.UpdateMachineState( Environment.MachineName, -1, EProgressionState.InstigatorConnected ); } // Add to the Agent-wide list of active jobs JobGuid = NewJobGuid; Manager.ActiveJobs.Add( NewJobGuid, this ); return Constants.SUCCESS; }
public AgentConfiguration() { AgentProcessID = -1; AgentCachePath = null; AgentJobGuid = null; IsPureLocalConnection = false; }
public Int32 GetActiveJobGuid( Int32 ConnectionHandle, ref AgentGuid ActiveJobGuid ) { StartTiming( "GetActiveJobGuid-Internal", true ); ActiveJobGuid = null; Int32 ErrorCode = Constants.INVALID; Connection JobOwner; if( Connections.TryGetValue( ConnectionHandle, out JobOwner ) ) { if( JobOwner.Job != null ) { ActiveJobGuid = JobOwner.Job.JobGuid; ErrorCode = Constants.SUCCESS; } } else { Log( EVerbosityLevel.Critical, ELogColour.Red, "[Job] GetActiveJobGuid: Rejected, unrecognized connection" ); ErrorCode = Constants.ERROR_CONNECTION_NOT_FOUND; } StopTiming(); return ErrorCode; }
/** * Called by a remote Agent, this provides the data for a new channel being pushed */ public bool SendChannel( Int32 ConnectionHandle, string ChannelName, byte[] ChannelData, AgentGuid JobGuid ) { StartTiming( "SendChannel-Internal", true ); bool bSucceeded = false; // Validate the calling connection Connection ConnectionRequestingChannel; if( Connections.TryGetValue( ConnectionHandle, out ConnectionRequestingChannel ) && ConnectionRequestingChannel is RemoteConnection ) { EChannelFlags ChannelFlags = EChannelFlags.ACCESS_WRITE; if( JobGuid == null ) { ChannelFlags |= EChannelFlags.TYPE_PERSISTENT; } else { ChannelFlags |= EChannelFlags.TYPE_JOB_ONLY; } Hashtable OpenInParameters = new Hashtable(); OpenInParameters["Version"] = ESwarmVersionValue.VER_1_0; OpenInParameters["ChannelName"] = ChannelName; OpenInParameters["ChannelFlags"] = ChannelFlags; Hashtable OpenOutParameters = null; Int32 LocalChannelHandle = OpenChannel_1_0( ConnectionHandle, OpenInParameters, ref OpenOutParameters ); if( LocalChannelHandle >= 0 ) { // Set up the file name string FullChannelName; if( JobGuid == null ) { string AgentStagingArea = Path.Combine( AgentApplication.Options.CacheFolder, "AgentStagingArea" ); FullChannelName = Path.Combine( AgentStagingArea, ChannelName ); } else { string AllJobsFolder = Path.Combine( AgentApplication.Options.CacheFolder, "Jobs" ); string ThisJobFolder = Path.Combine( AllJobsFolder, "Job-" + JobGuid.ToString() ); FullChannelName = Path.Combine( ThisJobFolder, ChannelName ); } // Open the FileStream and write the data directly in FileStream NewChannel = null; Int32 NewChannelBytes = 0; try { NewChannel = new FileStream( FullChannelName, FileMode.Create, FileAccess.Write, FileShare.None ); NewChannelBytes = ChannelData.Length; NewChannel.Write( ChannelData, 0, NewChannelBytes ); NewChannel.Close(); } catch( Exception Ex ) { Log( EVerbosityLevel.Informative, ELogColour.Orange, "[SendChannel] Channel \"" + ChannelName + "\" not transferred because of name collision. Channel with that name already exists" ); Log( EVerbosityLevel.Verbose, ELogColour.Orange, "[SendChannel] Exception: " + Ex.ToString() ); } // Close the channel now that we're done Hashtable CloseInParameters = new Hashtable(); CloseInParameters["Version"] = ESwarmVersionValue.VER_1_0; CloseInParameters["ChannelHandle"] = LocalChannelHandle; Hashtable CloseOutParameters = null; if( CloseChannel_1_0( ConnectionHandle, CloseInParameters, ref CloseOutParameters ) >= 0 ) { // Success bSucceeded = true; // Track the number of bytes received over the network ConnectionRequestingChannel.NetworkBytesReceived += NewChannelBytes; if( ConnectionRequestingChannel.Job != null ) { ConnectionRequestingChannel.Job.NetworkBytesReceived += NewChannelBytes; } if( ConnectionRequestingChannel.Parent != null ) { ConnectionRequestingChannel.Parent.NetworkBytesReceived += NewChannelBytes; } } } } StopTiming(); return bSucceeded; }
/** * Called by a remote Agent, this requests that a specified file is pushed back */ public bool RequestChannel( Int32 ConnectionHandle, string ChannelName, AgentGuid JobGuid ) { // Validate the calling connection Connection ConnectionRequestingChannel; if( Connections.TryGetValue( ConnectionHandle, out ConnectionRequestingChannel ) && ConnectionRequestingChannel is RemoteConnection ) { // Push it back across to the remote Agent return PushChannel( ConnectionRequestingChannel as RemoteConnection, ChannelName, JobGuid ); } return false; }
/** * Pushes a local channel to the remote agent via the remote connection parameter * by calling SendChannel on the remote agent */ public bool PushChannel(RemoteConnection Remote, string ChannelName, AgentGuid JobGuid) { StartTiming("PushChannel-Internal", true); bool bChannelTransferred = false; // The remote connection's handle can be used for all interaction because // it has the same meaning on both ends of the connection Int32 ConnectionHandle = Remote.Handle; EChannelFlags ChannelFlags = EChannelFlags.ACCESS_READ; if (JobGuid == null) { ChannelFlags |= EChannelFlags.TYPE_PERSISTENT; } else { ChannelFlags |= EChannelFlags.TYPE_JOB_ONLY; } Hashtable OpenInParameters = new Hashtable(); OpenInParameters["Version"] = ESwarmVersionValue.VER_1_0; OpenInParameters["ChannelName"] = ChannelName; OpenInParameters["ChannelFlags"] = ChannelFlags; Hashtable OpenOutParameters = null; Int32 LocalChannelHandle = OpenChannel_1_0(ConnectionHandle, OpenInParameters, ref OpenOutParameters); if (LocalChannelHandle >= 0) { try { string FullChannelName; if (JobGuid == null) { FullChannelName = Path.Combine(AgentApplication.Options.CacheFolder, ChannelName); } else { string AllJobsFolder = Path.Combine(AgentApplication.Options.CacheFolder, "Jobs"); string ThisJobFolder = Path.Combine(AllJobsFolder, "Job-" + JobGuid.ToString()); FullChannelName = Path.Combine(ThisJobFolder, ChannelName); } // Read the entire file into a byte stream byte[] ChannelData = File.ReadAllBytes(FullChannelName); // Send the entire channel at once bChannelTransferred = Remote.Interface.SendChannel(ConnectionHandle, ChannelName, ChannelData, JobGuid); // If the channel was transferred, track the number of bytes that actually moved across the network if (bChannelTransferred) { FileInfo ChannelInfo = new FileInfo(FullChannelName); Remote.NetworkBytesSent += ChannelInfo.Length; if (Remote.Job != null) { Remote.Job.NetworkBytesSent += ChannelInfo.Length; } if (Remote.Parent != null) { Remote.Parent.NetworkBytesSent += ChannelInfo.Length; } } } catch (Exception Ex) { Log(EVerbosityLevel.Verbose, ELogColour.Red, "[PushChannel] Exception message: " + Ex.ToString()); } Hashtable CloseInParameters = new Hashtable(); CloseInParameters["Version"] = ESwarmVersionValue.VER_1_0; CloseInParameters["ChannelHandle"] = LocalChannelHandle; Hashtable CloseOutParameters = null; CloseChannel_1_0(ConnectionHandle, CloseInParameters, ref CloseOutParameters); if (bChannelTransferred) { Log(EVerbosityLevel.Verbose, ELogColour.Green, "[Channel] Successful channel push of " + ChannelName); } else { Log(EVerbosityLevel.Verbose, ELogColour.Red, string.Format("[PushChannel] Pushing the channel {0} has failed!", ChannelName)); } } else { Log(EVerbosityLevel.Informative, ELogColour.Red, string.Format("[PushChannel] Cannot open local channel {0}.", ChannelName)); } StopTiming(); return bChannelTransferred; }
/** * Pulls a remote channel from the remote agent via the remote connection parameter. * * @param Remote Remote connection. * @param ChannelName The name of the file to pull. * @param JobGuid A guid of the job. * @param RetriesOnFailure How many times should the pull fail until return a failure. * * @returns True on success. False otherwise. */ public bool PullChannel(RemoteConnection Remote, string ChannelName, AgentGuid JobGuid, int RetriesOnFailure = int.MaxValue) { StartTiming("PullChannel-Internal", true); // The remote connection's handle can be used for all interaction because // it has the same meaning on both ends of the connection Int32 ConnectionHandle = Remote.Handle; // Request the file, which will push it back, and keep doing so until we get it // or until the connection is dead, which ever comes first bool bChannelTransferred = false; int TryId = 0; while ((Remote.Interface.IsAlive()) && (bChannelTransferred == false) && (TryId < RetriesOnFailure)) { try { bChannelTransferred = Remote.Interface.RequestChannel(ConnectionHandle, ChannelName, JobGuid); } catch (Exception Ex) { Log(EVerbosityLevel.Verbose, ELogColour.Red, "[PullChannel] Exception message: " + Ex.ToString()); } if(!bChannelTransferred) { Log(EVerbosityLevel.Verbose, ELogColour.Red, string.Format("[PullChannel] Pulling the channel {0} has failed! Retry {1} of {2}.", ChannelName, TryId + 1, RetriesOnFailure)); } ++TryId; } StopTiming(); return bChannelTransferred; }
/////////////////////////////////////////////////////////////////////////// /** * Standard constructor */ public JobChannel( AgentGuid NewJobGuid, string ChannelName, string FullChannelName, EChannelFlags ChannelFlags ) : base(ChannelName, FullChannelName, ChannelFlags) { JobGuid = NewJobGuid; }
/////////////////////////////////////////////////////////////////////////// public Int32 OpenJob(Int32 ConnectionHandle, AgentGuid JobGuid ) { OpenJobDelegate DOpenJob = Connection.OpenJob; // Set up the versioned hashtable input parameters Hashtable InParameters = new Hashtable(); InParameters["Version"] = ESwarmVersionValue.VER_1_0; InParameters["JobGuid"] = JobGuid; // Invoke the method, then wait for it to finish or to be notified that the connection dropped Hashtable OutParameters = null; IAsyncResult Result = DOpenJob.BeginInvoke(ConnectionHandle, InParameters, ref OutParameters, null, null); WaitHandle.WaitAny(new WaitHandle[]{ Result.AsyncWaitHandle, ConnectionDroppedEvent }); // If the method completed normally, return the result if (Result.IsCompleted) { // If the invocation completed, success return DOpenJob.EndInvoke(ref OutParameters, Result); } // Otherwise, error return Constants.ERROR_CONNECTION_DISCONNECTED; }
/* * Generates the full channel name, including Job path and staging area path if necessary */ String GenerateFullChannelName(String ManagedChannelName, EChannelFlags ChannelFlags) { if ((ChannelFlags & EChannelFlags.TYPE_PERSISTENT) != 0) { if ((ChannelFlags & EChannelFlags.ACCESS_WRITE) != 0) { // A persistent cache channel open for writing opens in the staging area String StagingAreaName = Path.Combine(AgentCacheFolder, "AgentStagingArea"); return Path.Combine(StagingAreaName, ManagedChannelName); } else if ((ChannelFlags & EChannelFlags.ACCESS_READ) != 0) { // A persistent cache channel open for reading opens directly in the cache return Path.Combine(AgentCacheFolder, ManagedChannelName); } } else if ((ChannelFlags & EChannelFlags.TYPE_JOB_ONLY) != 0) { AgentGuid JobGuid = ConnectionConfiguration.AgentJobGuid; if (JobGuid == null) { // If there's no Job associated with this connection at this point, provide // a default GUID for one for debugging access to the agent cache JobGuid = new AgentGuid(0x00000123, 0x00004567, 0x000089ab, 0x0000cdef); } // A Job Channel opens directly in the Job-specific directory String JobsFolder = Path.Combine(AgentCacheFolder, "Jobs"); String JobFolderName = Path.Combine(JobsFolder, "Job-" + JobGuid.ToString()); return Path.Combine(JobFolderName, ManagedChannelName); } return ""; }
/** * Adds a Task to the current Job * * @param Specification A structure describing the new Task * * @return Int32 Error code (< 0 is an error) */ public virtual Int32 AddTask(FTaskSpecification Specification) { StartTiming("AddTask-Managed", true); Int32 ReturnValue = Constants.INVALID; if (Connection != null) { if (ConnectionConfiguration.AgentJobGuid != null) { // Convert the parameters from native to managed AgentGuid TaskGuid = new AgentGuid(Specification.TaskGuid.A, Specification.TaskGuid.B, Specification.TaskGuid.C, Specification.TaskGuid.D); String Parameters = Specification.Parameters; List<String> Dependencies = null; if (Specification.DependencyCount > 0) { Dependencies = new List<String>(); for (UInt32 i = 0; i < Specification.DependencyCount; i++) { Dependencies.Add(Specification.Dependencies[i]); } } AgentTaskSpecification NewSpecification = new AgentTaskSpecification(ConnectionConfiguration.AgentJobGuid, TaskGuid, (Int32)Specification.Flags, Parameters, (Int32)Specification.Cost, Dependencies); // Ensure all the files are in the cache with the right cache compatible name ReturnValue = CacheAllFiles(NewSpecification); if (ReturnValue >= 0) { // Queue up all tasks until the specification is complete and submit them all at once PendingTasks.Add(NewSpecification); } } else { ReturnValue = Constants.ERROR_JOB_NOT_FOUND; } } else { ReturnValue = Constants.ERROR_CONNECTION_NOT_FOUND; } StopTiming(); return ReturnValue; }
/** * Opens a Job session, which allows a Job to be specified, Tasks added, Job * channels opened and used, etc. When the Job is complete and no more Job * related data is needed from the Swarm, call CloseJob. * * @param JobGuid A GUID that uniquely identifies this Job, generated by the caller * * @return Int32 Error code (< 0 is an error) */ public virtual Int32 OpenJob(FGuid JobGuid) { StartTiming("OpenJob-Managed", true); Int32 ReturnValue = Constants.INVALID; if (Connection != null) { StartTiming("OpenJob-Remote", false); try { AgentGuid ManagedJobGuid = new AgentGuid(JobGuid.A, JobGuid.B, JobGuid.C, JobGuid.D); ReturnValue = Connection.OpenJob(ConnectionHandle, ManagedJobGuid); if (ReturnValue >= 0) { // If the call was successful, assign the Job Guid as the active one ConnectionConfiguration.AgentJobGuid = ManagedJobGuid; // Allocate a new list to collect tasks until the specification is complete PendingTasks = new List<AgentTaskSpecification>(); } } catch (Exception Ex) { Log(EVerbosityLevel.Critical, ELogColour.Red, "[Interface:OpenJob] Error: " + Ex.Message); ReturnValue = Constants.ERROR_CONNECTION_DISCONNECTED; CleanupClosedConnection(); } StopTiming(); } else { ReturnValue = Constants.ERROR_CONNECTION_NOT_FOUND; } StopTiming(); return ReturnValue; }
/** * Sends a message to an Agent (return messages are sent via the FConnectionCallback) * * @param Message The message being sent * * @return Int32 error code (< 0 is error) */ public virtual Int32 SendMessage(IntPtr NativeMessagePtr) { StartTiming("SendMessage-Managed", true); FMessage NativeMessage = (FMessage)Marshal.PtrToStructure(NativeMessagePtr, typeof(FMessage)); Int32 ReturnValue = Constants.INVALID; if (Connection != null) { AgentMessage ManagedMessage = null; // 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 (NativeMessage.Version == ESwarmVersionValue.VER_1_0) { switch (NativeMessage.Type) { case EMessageType.TASK_REQUEST_RESPONSE: // Swallow this message, since it should not be sent along to a local connection // since all Job and Task information is contained within the Agent itself break; case EMessageType.TASK_STATE: { FTaskState NativeTaskStateMessage = (FTaskState)Marshal.PtrToStructure(NativeMessagePtr, typeof(FTaskState)); AgentGuid ManagedTaskGuid = new AgentGuid(NativeTaskStateMessage.TaskGuid.A, NativeTaskStateMessage.TaskGuid.B, NativeTaskStateMessage.TaskGuid.C, NativeTaskStateMessage.TaskGuid.D); EJobTaskState TaskState = (EJobTaskState)NativeTaskStateMessage.TaskState; AgentTaskState ManagedTaskStateMessage = new AgentTaskState(null, ManagedTaskGuid, TaskState); ManagedTaskStateMessage.TaskExitCode = NativeTaskStateMessage.TaskExitCode; ManagedTaskStateMessage.TaskRunningTime = NativeTaskStateMessage.TaskRunningTime; // If there is a message, be sure copy and pass it on if (NativeTaskStateMessage.TaskMessage != IntPtr.Zero) { ManagedTaskStateMessage.TaskMessage = FStringMarshaler.MarshalNativeToManaged(NativeTaskStateMessage.TaskMessage); } ManagedMessage = ManagedTaskStateMessage; } break; case EMessageType.INFO: { // Create the managed version of the info message FInfoMessage NativeInfoMessage = (FInfoMessage)Marshal.PtrToStructure(NativeMessagePtr, typeof(FInfoMessage)); AgentInfoMessage ManagedInfoMessage = new AgentInfoMessage(); if (NativeInfoMessage.TextMessage != IntPtr.Zero) { ManagedInfoMessage.TextMessage = FStringMarshaler.MarshalNativeToManaged(NativeInfoMessage.TextMessage); } ManagedMessage = ManagedInfoMessage; } break; case EMessageType.ALERT: { // Create the managed version of the alert message FAlertMessage NativeAlertMessage = (FAlertMessage)Marshal.PtrToStructure(NativeMessagePtr, typeof(FAlertMessage)); AgentGuid JobGuid = new AgentGuid(NativeAlertMessage.JobGuid.A, NativeAlertMessage.JobGuid.B, NativeAlertMessage.JobGuid.C, NativeAlertMessage.JobGuid.D); AgentAlertMessage ManagedAlertMessage = new AgentAlertMessage(JobGuid); ManagedAlertMessage.AlertLevel = (EAlertLevel)(NativeAlertMessage.AlertLevel); AgentGuid ObjectGuid = new AgentGuid(NativeAlertMessage.ObjectGuid.A, NativeAlertMessage.ObjectGuid.B, NativeAlertMessage.ObjectGuid.C, NativeAlertMessage.ObjectGuid.D); ManagedAlertMessage.ObjectGuid = ObjectGuid; ManagedAlertMessage.TypeId = NativeAlertMessage.TypeId; if (NativeAlertMessage.TextMessage != IntPtr.Zero) { ManagedAlertMessage.TextMessage = FStringMarshaler.MarshalNativeToManaged(NativeAlertMessage.TextMessage); } ManagedMessage = ManagedAlertMessage; } break; case EMessageType.TIMING: { // Create the managed version of the info message FTimingMessage NativeTimingMessage = (FTimingMessage)Marshal.PtrToStructure(NativeMessagePtr, typeof(FTimingMessage)); AgentTimingMessage ManagedTimingMessage = new AgentTimingMessage((EProgressionState)NativeTimingMessage.State, NativeTimingMessage.ThreadNum); ManagedMessage = ManagedTimingMessage; } break; default: // By default, just pass the message version and type through, but // any additional payload of a specialized type will be lost ManagedMessage = new AgentMessage((EMessageType)NativeMessage.Type); break; } } if (ManagedMessage != null) { try { // Finally, send the message to the Agent StartTiming("SendMessage-Remote", false); Connection.SendMessage(ConnectionHandle, ManagedMessage); StopTiming(); ReturnValue = Constants.SUCCESS; } catch (Exception Ex) { Log(EVerbosityLevel.Critical, ELogColour.Red, "[Interface:SendMessage] Error: " + Ex.Message); ReturnValue = Constants.ERROR_CONNECTION_DISCONNECTED; CleanupClosedConnection(); } } } else { ReturnValue = Constants.ERROR_CONNECTION_NOT_FOUND; } StopTiming(); return( ReturnValue ); }
public bool SendChannel( Int32 ConnectionHandle, string ChannelName, byte[] ChannelData, AgentGuid JobGuid ) { bool ReturnCode = false; if( RemoteInterfaceAlive ) { try { SendChannelDelegate DSendChannel = new SendChannelDelegate( RemoteInterface.SendChannel ); IAsyncResult Result = DSendChannel.BeginInvoke( ConnectionHandle, ChannelName, ChannelData, JobGuid, null, null ); WaitHandle.WaitAny( new WaitHandle[2] { Result.AsyncWaitHandle, RemoteInterfaceDropped } ); if( Result.IsCompleted ) { ReturnCode = DSendChannel.EndInvoke( Result ); } } catch( Exception ) { SignalConnectionDropped(); } } return ReturnCode; }
public bool RequestChannel( Int32 ConnectionHandle, string ChannelName, AgentGuid JobGuid ) { bool ReturnCode = false; if( RemoteInterfaceAlive ) { RetryCatch( // Try { () => { RequestChannelDelegate DRequestChannel = new RequestChannelDelegate(RemoteInterface.RequestChannel); IAsyncResult Result = DRequestChannel.BeginInvoke(ConnectionHandle, ChannelName, JobGuid, null, null); WaitHandle.WaitAny(new WaitHandle[2] { Result.AsyncWaitHandle, RemoteInterfaceDropped }); if (Result.IsCompleted) { ReturnCode = DRequestChannel.EndInvoke(Result); } }, // } Catch (Exception) { () => { SignalConnectionDropped(); }, // } 5 ); } return ReturnCode; }