Esempio n. 1
0
        /// <summary>
        /// Created a new threaded message response
        /// </summary>
        /// <param name="message">The message to thread from.</param>
        public static T CreateThreadedReply <T>(this AgentMessage message) where T : AgentMessage, new ()
        {
            var newMsg = new T();

            newMsg.ThreadMessage(message);
            return(newMsg);
        }
Esempio n. 2
0
 /// <summary>
 /// Adds return routing to message
 /// </summary>
 /// <param name="message">The message to add return routing</param>
 public static void AddReturnRouting(this AgentMessage message)
 {
     message.AddDecorator(new TransportDecorator
     {
         ReturnRoute = ReturnRouteTypes.all.ToString("G")
     }, DecoratorNames.TransportDecorator);
 }
Esempio n. 3
0
    private void onCollectingCompleted(GatheredMaterialConcept gatheredConcept, AgentMessage message)
    {
        AgentMessage reply = message.Reply(AgentMessage.PerformativeType.INFORM);

        reply.Content = gatheredConcept;
        Send(reply);
    }
Esempio n. 4
0
        /// <summary>
        /// Invoke the handler pipeline and process the passed message.
        /// </summary>
        /// <param name="body">The body.</param>
        /// <param name="wallet">The wallet.</param>
        /// <param name="pool">The pool.</param>
        /// <returns></returns>
        /// <exception cref="Exception">Expected inner message to be of type 'ForwardMessage'</exception>
        /// <exception cref="AgentFrameworkException">Couldn't locate a message handler for type {messageType}</exception>
        protected async Task <byte[]> ProcessAsync(byte[] body, Wallet wallet, Pool pool = null)
        {
            EnsureConfigured();

            var agentContext = new AgentContext {
                Wallet = wallet, Pool = pool
            };

            agentContext.AddNext(new MessagePayload(body, true));

            AgentMessage outgoingMessage = null;

            while (agentContext.TryGetNext(out var message) && outgoingMessage == null)
            {
                outgoingMessage = await ProcessMessage(agentContext, message);
            }

            if (outgoingMessage != null) // && dont duplex????
            {
                //TODO what happens when I fail to transmit the message? need to roll back the state of the internal message?
                await MessageService.SendToConnectionAsync(wallet, outgoingMessage,
                                                           agentContext.Connection);

                outgoingMessage = null;
            }

            byte[] response = null;
            if (outgoingMessage != null)
            {
                response = await MessageService.PrepareAsync(wallet, outgoingMessage, "");
            }

            return(response);
        }
Esempio n. 5
0
        private void SendData(Socket handler, AgentMessage message)
        {
            var encrypted = CryptoController.Encrypt(message);

            var response = new StringBuilder("HTTP/1.1 200 OK\r\n");

            response.Append(string.Format("X-Malware: SharpC2\r\n"));
            response.Append(string.Format("Content-Length: {0}\r\n", encrypted.Length));
            response.Append(string.Format("Date: {0}\r\n", DateTime.UtcNow.ToString("ddd, d MMM yyyy HH:mm:ss UTC")));
            response.Append("\r\n");

            var headers    = Encoding.UTF8.GetBytes(response.ToString());
            var dataToSend = new byte[encrypted.Length + headers.Length];

            Buffer.BlockCopy(headers, 0, dataToSend, 0, headers.Length);
            Buffer.BlockCopy(encrypted, 0, dataToSend, headers.Length, encrypted.Length);

            try
            {
                handler.BeginSend(dataToSend, 0, dataToSend.Length, 0, new AsyncCallback(SendCallback), handler);
            }
            catch
            {
                // socket may be forcibly closed if agent dies
            }
        }
Esempio n. 6
0
        public void AddAgentMessage()
        {
            using (var uow = new CapriconContext())
            {
                //retreive an existing agent
                var agentRepository = new AgentRepository(uow);
                var existingAgent   = agentRepository.GetAll().FirstOrDefault();

                Assert.IsNotNull(existingAgent);

                //retreive an existing message
                var messageRepository = new MessageRepository(uow);
                var existingMessage   = messageRepository.GetAll().LastOrDefault();

                Assert.IsNotNull(existingMessage);

                //create new agent messsage
                var newAgentMessage = new AgentMessage()
                {
                    Agent   = existingAgent,
                    Message = existingMessage
                };

                //add the new agent message to the repository
                var agentMessageRepository = new AgentMessageRepository(uow);
                agentMessageRepository.Add(newAgentMessage);

                try
                {
                    uow.SaveChanges();
                }
                catch (DbEntityValidationException ex)
                {
                    //Retrieve validation errors
                    ex.EntityValidationErrors.ToList().ForEach
                    (
                        v =>
                    {
                        v.ValidationErrors.ToList().ForEach
                        (
                            e =>
                        {
                            System.Diagnostics.Debug.WriteLine(e.ErrorMessage);
                        }
                        );
                    }
                    );

                    Assert.Fail("Test failed");
                }

                //retrieve saved object
                var uow1               = new CapriconContext();
                var repository         = new AgentMessageRepository(uow1);
                var savedAgentMessages = repository.GetAll().ToList();

                Assert.AreEqual(savedAgentMessages[0].Agent.FirstName, existingAgent.FirstName     = "Blaise");
                Assert.AreEqual(savedAgentMessages[0].Message.MessageId, existingMessage.MessageId = 1);
            };
        }
        public override async Task OnConnectedAsync()
        {
            var msg = new AgentMessage <RpcRequest>
            {
                Author = new Author(_uiAgent),
                Data   = new RpcRequest
                {
                    Type           = RpcRequestType.GetAllTasks,
                    RequestedAgent = AgentType.DbManager
                },
                MessageType = MessageType.DbRequest,
                SendDate    = DateTime.Now
            };
            var result =
                await _uiAgent.CallAsync <Dictionary <string, TaskWithSubTasks> >(msg, TimeSpan.FromSeconds(30));

            if (result != null)
            {
                //  _logger.LogInformation(JsonSerializer.Serialize(result.Data));
                await Clients.Caller.SendCoreAsync(SignalRMessages.TasksConnectAccepted.ToString(),
                                                   new object[] { result.Data });
            }

            await base.OnConnectedAsync();
        }
Esempio n. 8
0
    private void ClientConnectCallback(IAsyncResult ar)
    {
        Status.Set();

        var client = ar.AsyncState as TcpClient;

        try
        {
            client.EndConnect(ar);

            var stream = client.GetStream();

            var outbound = new AgentMessage {
                Metadata = Metadata
            };

            if (Outbound.Count > 0)
            {
                outbound = Outbound.Dequeue();
            }

            var encrypted = Crypto.Encrypt(outbound);
            var state     = new CommStateObject {
                Handler = client, Worker = stream
            };
            stream.BeginWrite(encrypted, 0, encrypted.Length, new AsyncCallback(ClientWriteCallback), state);
        }
        catch
        {
            // Agent has probably been closed or killed
            ModuleStatus = ModuleStatus.Stopped;
        }
    }
Esempio n. 9
0
    private void HandleMessage(AgentMessage message)
    {
        if (string.IsNullOrEmpty(message.Data.AgentID) || message.Data.AgentID.Equals(AgentMetadata.AgentID, StringComparison.OrdinalIgnoreCase))    // message is for this agent
        {
            if (!string.IsNullOrEmpty(message.Data.Module))
            {
                try
                {
                    var callBack = AgentModules
                                   .Where(m => m.Name.Equals(message.Data.Module, StringComparison.OrdinalIgnoreCase))
                                   .Select(m => m.Commands).FirstOrDefault()
                                   .Where(c => c.Name.Equals(message.Data.Command, StringComparison.OrdinalIgnoreCase))
                                   .Select(c => c.CallBack).FirstOrDefault();

                    callBack?.Invoke(message.Data.Data);
                }
                catch (Exception e)
                {
                    SendError(e.Message);
                }
            }
        }
        else // for a p2p agent
        {
            P2P.BroadcastMessage(message); // very lazy approach until i can figure out a solution
        }
    }
Esempio n. 10
0
        public override async Task <AgentMessage> ProcessRpcAsync(AgentMessage <RpcRequest> message)
        {
            if (message.MessageType == MessageType.FileRequest && message.Data.Args.Length > 0)
            {
                try
                {
                    var response = await GetFileAsync(message.Data.Args[0]);

                    return(new AgentMessage <byte[]>
                    {
                        Author = this,
                        Data = response,
                        MessageType = MessageType.RpcResponse
                    });
                }
                catch (Exception e)
                {
                    _logger.LogError("Error occured while downloading {@TaskId} in {@AgentName} with {@Exception}",
                                     message.Data.Args[0], nameof(FileWorkerAgentImpl), e.ToString());

                    return(new AgentMessage <byte[]>
                    {
                        Author = this,
                        MessageType = MessageType.RpcResponse
                    });
                }
            }

            return(null);
        }
Esempio n. 11
0
        private static void ThreadMessage(this AgentMessage messageToThread, AgentMessage messageToThreadFrom)
        {
            ThreadDecorator previousMessageThreadContext = null;

            try
            {
                previousMessageThreadContext = messageToThreadFrom.GetDecorator <ThreadDecorator>(DecoratorIdentifier);
            }
            catch (AriesFrameworkException) { }

            ThreadDecorator currentThreadContext;

            if (previousMessageThreadContext != null)
            {
                currentThreadContext = new ThreadDecorator
                {
                    ParentThreadId = previousMessageThreadContext.ParentThreadId,
                    ThreadId       = previousMessageThreadContext.ThreadId
                };
            }
            else
            {
                currentThreadContext = new ThreadDecorator
                {
                    ThreadId = messageToThreadFrom.Id
                };
            }


            messageToThread.AddDecorator(currentThreadContext, DecoratorIdentifier);
        }
Esempio n. 12
0
        public override async Task ProcessMessageAsync(AgentMessage message)
        {
            try
            {
                switch (message.MessageType)
                {
                case MessageType.Connection:
                    var connectionMessage = message.Data.ToObject <ConnectionMessage>();
                    connectionMessage.Who ??= message.Author;
                    await _agentUiHub.Clients.All.SendAsync(SignalRMessages.AgentConnections.ToString(),
                                                            connectionMessage);

                    break;

                case MessageType.WorkerTask:
                case MessageType.TaskStat:
                    var task = message.Data.ToObject <TaskMessage>();
                    task.Data       = new byte[0];
                    task.WorkerName = message.Author.SubType;
                    await _taskUiHub.Clients.All.SendAsync(SignalRMessages.TaskStateChanged.ToString(), task);

                    break;
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Can`t process message");
            }
        }
Esempio n. 13
0
    private void StartClient()
    {
        Task.Factory.StartNew(delegate()
        {
            while (ModuleStatus == ModuleStatus.Running)
            {
                Status.Reset();
                var pipe = new NamedPipeClientStream(ConnectHost, Pipename, PipeDirection.InOut, PipeOptions.Asynchronous);
                pipe.Connect(5000);

                var outbound = new AgentMessage {
                    Metadata = Metadata
                };

                if (Outbound.Count > 0)
                {
                    outbound = Outbound.Dequeue();
                }

                var dataToSend = Crypto.Encrypt(outbound);

                pipe.BeginWrite(dataToSend, 0, dataToSend.Length, new AsyncCallback(ClientWriteCallback), pipe);

                Status.WaitOne();

                Thread.Sleep(1000);
            }
        });
    }
Esempio n. 14
0
        /// <summary>
        /// Prepares a wire level message from the application level agent message asynchronously
        /// this includes packing the message and wrapping it in required forward messages
        /// if the message requires it.
        /// </summary>
        /// <param name="wallet">The wallet.</param>
        /// <param name="message">The message context.</param>
        /// <param name="recipientKey">The key to encrypt the message for.</param>
        /// <param name="routingKeys">The routing keys to pack the message for.</param>
        /// <param name="senderKey">The sender key to encrypt the message from.</param>
        /// <returns>The response async.</returns>
        public static async Task <byte[]> PrepareAsync(Wallet wallet, AgentMessage message, string recipientKey, string[] routingKeys = null, string senderKey = null)
        {
            if (message == null)
            {
                throw new ArgumentNullException(nameof(message));
            }
            if (recipientKey == null)
            {
                throw new ArgumentNullException(nameof(recipientKey));
            }

            // Pack application level message
            var msg = await PackAsync(wallet, recipientKey, message.ToByteArray(), senderKey);

            var previousKey = recipientKey;

            if (routingKeys != null)
            {
                // TODO: In case of multiple key, should they each wrap a forward message
                // or pass all keys to the PackAsync function as array?
                foreach (var routingKey in routingKeys)
                {
                    // Anonpack
                    msg = await PackAsync(wallet, routingKey, new ForwardMessage { Message = JObject.Parse(msg.GetUTF8String()), To = previousKey });

                    previousKey = routingKey;
                }
            }

            return(msg);
        }
Esempio n. 15
0
 // Получение сообщения от другого агента
 public override void EventMessage(AgentMessage message)
 {
     if (message.message == Enums.MessageType.Infected.ToString() &&
         healthState == Enums.HealthState.Susceptible)
     {
         isBeingInfected = true;
     }
 }
Esempio n. 16
0
 public override async Task ProcessMessageAsync(AgentMessage message)
 {
     if (message.MessageType == MessageType.DeleteFile)
     {
         var taskId = message.To <string>().Data;
         await DeleteFileAsync(taskId);
     }
 }
Esempio n. 17
0
        public void BroadcastMessage(AgentMessage message)
        {
            var modules = P2PAgents.Values.ToList();

            foreach (var module in modules)
            {
                module.SendData(message);
            }
        }
Esempio n. 18
0
        /// <summary>
        /// Removes the attachment.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="nickname">The nickname.</param>
        /// <returns></returns>
        public static bool RemoveAttachment(this AgentMessage message, string nickname)
        {
            var decorator = message.FindDecorator <AttachDecorator>("attach") ?? new AttachDecorator();
            var result    = decorator.Remove(decorator[nickname]);

            message.SetDecorator(decorator, "attach");

            return(result);
        }
Esempio n. 19
0
    /// Listens for actions, memories, and values and sends them
    /// to the corrensponding brains.
    public void UpdateActions()
    {
        // TO MODIFY	--------------------------------------------
        sender.Send(Encoding.ASCII.GetBytes("STEPPING"));
        string       a            = Receive();
        AgentMessage agentMessage = null;

        try
        {
            agentMessage = JsonConvert.DeserializeObject <AgentMessage>(a);
        }
        catch (Exception e)
        {
            Debug.Log(a);
            Debug.Log(e);
        }

        foreach (Brain brain in brains)
        {
            if (brain.brainType == BrainType.External)
            {
                string brainName = brain.gameObject.name;

                Dictionary <int, float[]> actionDict = new Dictionary <int, float[]>();
                for (int i = 0; i < current_agents[brainName].Count; i++)
                {
                    if (brain.brainParameters.actionSpaceType == StateType.continuous)
                    {
                        actionDict.Add(current_agents[brainName][i],
                                       agentMessage.action[brainName].GetRange(i * brain.brainParameters.actionSize, brain.brainParameters.actionSize).ToArray());
                    }
                    else
                    {
                        actionDict.Add(current_agents[brainName][i],
                                       agentMessage.action[brainName].GetRange(i, 1).ToArray());
                    }
                }
                storedActions[brainName] = actionDict;

                Dictionary <int, float[]> memoryDict = new Dictionary <int, float[]>();
                for (int i = 0; i < current_agents[brainName].Count; i++)
                {
                    memoryDict.Add(current_agents[brainName][i],
                                   agentMessage.memory[brainName].GetRange(i * brain.brainParameters.memorySize, brain.brainParameters.memorySize).ToArray());
                }
                storedMemories[brainName] = memoryDict;

                Dictionary <int, float> valueDict = new Dictionary <int, float>();
                for (int i = 0; i < current_agents[brainName].Count; i++)
                {
                    valueDict.Add(current_agents[brainName][i],
                                  agentMessage.value[brainName][i]);
                }
                storedValues[brainName] = valueDict;
            }
        }
    }
Esempio n. 20
0
        /// <summary>
        /// Threads the current message.
        /// </summary>
        /// <param name="messageToThread">Message to thread.</param>
        /// <param name="threadId">Thread id to thread the message with.</param>
        public static void ThreadFrom(this AgentMessage messageToThread, string threadId)
        {
            var currentThreadContext = new ThreadDecorator
            {
                ThreadId = threadId
            };

            messageToThread.AddDecorator(currentThreadContext, DecoratorIdentifier);
        }
Esempio n. 21
0
        /// <summary>
        /// Prepares a wire level message from the application level agent message for a connection asynchronously
        /// this includes packing the message and wrapping it in required forward messages
        /// if the message requires it.
        /// </summary>
        /// <param name="wallet">The wallet.</param>
        /// <param name="message">The message context.</param>
        /// <param name="connection">The connection to prepare the message for.</param>
        /// <returns>The response async.</returns>
        public static Task <byte[]> PrepareAsync(Wallet wallet, AgentMessage message, ConnectionRecord connection)
        {
            var recipientKey = connection.TheirVk
                               ?? throw new AriesFrameworkException(ErrorCode.A2AMessageTransmissionError, "Cannot find encryption key");

            var routingKeys = connection.Endpoint?.Verkey != null ? connection.Endpoint.Verkey : new string[0];

            return(PrepareAsync(wallet, message, recipientKey, routingKeys, connection.MyVk));
        }
Esempio n. 22
0
        protected override void Action()
        {
            AgentMessage message = getMessage();

            while (message != null)
            {
                Agent.PreProcessMessage(message);
                message = getMessage();
            }
        }
Esempio n. 23
0
    override protected void Action()
    {
        MaterialConcept materialConcept = new MaterialConcept(materialType);
        AgentAction     action          = new GetMaterialAction(materialConcept, amount);
        AgentMessage    message         = new AgentMessage(AgentMessage.PerformativeType.INFORM);

        message.Receiver = AgentId.ParseGlobalId(receiver);
        message.Content  = action;
        Agent.Send(message);
    }
Esempio n. 24
0
        private static DidExchangeProblemReportMessage CreateProblemReportMessage(AgentMessage message)
        {
            var response = message.CreateThreadedReply <DidExchangeProblemReportMessage>();

            response.ProblemCode = message is DidExchangeRequestMessage
                ? DidExchangeProblemReportMessage.Error.RequestProcessingError
                : DidExchangeProblemReportMessage.Error.ResponseProcessingError;

            return(response);
        }
Esempio n. 25
0
        private async Task ScanInvite()
        {
            var expectedFormat = ZXing.BarcodeFormat.QR_CODE;

            var opts = new ZXing.Mobile.MobileBarcodeScanningOptions {
                PossibleFormats = new List <ZXing.BarcodeFormat> {
                    expectedFormat
                }
            };

            var context = await _agentContextProvider.GetContextAsync();

            var scanner = new ZXing.Mobile.MobileBarcodeScanner();

            var result = await scanner.Scan(opts);

            if (result == null)
            {
                return;
            }

            AgentMessage message = await MessageDecoder.ParseMessageAsync(result.Text);

            switch (message)
            {
            case ConnectionInvitationMessage invitation:
                break;

            case RequestPresentationMessage presentation:
                RequestPresentationMessage proofRequest = (RequestPresentationMessage)presentation;
                var         service     = message.GetDecorator <ServiceDecorator>(DecoratorNames.ServiceDecorator);
                ProofRecord proofRecord = await _proofService.ProcessRequestAsync(context, proofRequest, null);

                proofRecord.SetTag("RecipientKey", service.RecipientKeys.ToList()[0]);
                proofRecord.SetTag("ServiceEndpoint", service.ServiceEndpoint);
                await _recordService.UpdateAsync(context.Wallet, proofRecord);

                _eventAggregator.Publish(new ApplicationEvent {
                    Type = ApplicationEventType.ProofRequestUpdated
                });
                break;

            default:
                DialogService.Alert("Invalid invitation!");
                return;
            }

            Device.BeginInvokeOnMainThread(async() =>
            {
                if (message is ConnectionInvitationMessage)
                {
                    await NavigationService.NavigateToAsync <AcceptInviteViewModel>(message as ConnectionInvitationMessage, NavigationType.Modal);
                }
            });
        }
Esempio n. 26
0
 private Action <GatheredMaterialConcept> getActionOnCollectingCompleted(AgentMessage message)
 {
     if (message.Protocol == Protocols.FIPA_REQUEST)
     {
         return(delegate(GatheredMaterialConcept concept) { onCollectingCompleted(concept, message); });
     }
     else
     {
         return(null);
     }
 }
Esempio n. 27
0
        public override void Step()
        {
            NotifyServerDataReceived();
            string           jsonData = _communicator.ReceiveFromServer();
            AgentMessage     message  = JsonConvert.DeserializeObject <AgentMessage>(jsonData);
            AgentStepMessage stepMsg  = _env.Step((Action)message.Action);
            string           stepData = JsonConvert.SerializeObject(stepMsg, Formatting.Indented);

            SendDataBytesToServer(Encoding.ASCII.GetBytes(stepData));
            SendDataBytesToServer(_env.GetEnvironmentImageBytes());
        }
        /// <inheritdoc />
        public virtual Task <byte[]> PrepareAsync(Wallet wallet, AgentMessage message, ConnectionRecord connection, string recipientKey = null, bool useRoutingKeys = true)
        {
            recipientKey = recipientKey
                           ?? connection.TheirVk
                           ?? throw new AgentFrameworkException(
                                     ErrorCode.A2AMessageTransmissionError, "Cannot find encryption key");

            var routingKeys = useRoutingKeys && connection.Endpoint?.Verkey != null ? new[] { connection.Endpoint.Verkey } : new string[0];

            return(PrepareAsync(wallet, message, recipientKey, routingKeys, connection.MyVk));
        }
Esempio n. 29
0
        public AgentMessage Reply(PerformativeType performative)
        {
            AgentMessage reply = this.MemberwiseClone() as AgentMessage;

            reply.Performative = performative;
            reply.Sender       = this.RealReceiver;
            reply.Receiver     = this.Sender;
            reply.RealReceiver = this.Sender;
            reply.InReplyTo    = this.ReplyWith;
            return(reply);
        }
Esempio n. 30
0
        public bool RecvData(out AgentMessage message)
        {
            if (InboundC2Data.Count > 0)
            {
                message = InboundC2Data.Dequeue();
                return(true);
            }

            message = null;
            return(false);
        }
Esempio n. 31
0
        /**
         * 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 );
        }
		///////////////////////////////////////////////////////////////////////////
		
		public Int32 GetMessage(Int32 ConnectionHandle, out AgentMessage NextMessage, Int32 Timeout)
		{
			GetMessageDelegate DGetMessage = Connection.GetMessage;
			
			// Set up the versioned hashtable input parameters
			Hashtable InParameters = new Hashtable();
			InParameters["Version"] = ESwarmVersionValue.VER_1_0;
			InParameters["Timeout"] = (Int32)Timeout;
			
			// Invoke the method, then wait for it to finish or to be notified that the connection dropped
			Hashtable OutParameters = null;
			IAsyncResult Result = DGetMessage.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 didn't fail, end to get the result
				Int32 ReturnValue = DGetMessage.EndInvoke(ref OutParameters, Result);
				if (OutParameters != null)
				{
					if((ESwarmVersionValue)OutParameters["Version"] == ESwarmVersionValue.VER_1_0)
					{
						NextMessage = (AgentMessage )OutParameters["Message"];
						
						// Complete and successful
						return ReturnValue;
					}
				}
			}
			// Otherwise, error
			NextMessage = null;
			return Constants.ERROR_CONNECTION_DISCONNECTED;
		}
		///////////////////////////////////////////////////////////////////////////
		
		public Int32 SendMessage(Int32 ConnectionHandle, AgentMessage NewMessage)
		{
			SendMessageDelegate DSendMessage = Connection.SendMessage;
			
			// Set up the versioned hashtable input parameters
			Hashtable InParameters = new Hashtable();
			InParameters["Version"] = ESwarmVersionValue.VER_1_0;
			InParameters["Message"] = NewMessage;
			
			// Invoke the method, then wait for it to finish or to be notified that the connection dropped
			Hashtable OutParameters = null;
			IAsyncResult Result = DSendMessage.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 DSendMessage.EndInvoke(ref OutParameters, Result);
			}
			// Otherwise, error
			return Constants.ERROR_CONNECTION_DISCONNECTED;
		}
		/**
		 * 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 );
		}