source: branches/eraser6/Manager/RemoteExecutor.cs @ 738

Revision 738, 12.1 KB checked in by lowjoel, 6 years ago (diff)

Include the User SID when creating a server instance so that multi-user scenarios are taken care of.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
RevLine 
[610]1/*
2 * $Id$
3 * Copyright 2008 The Eraser Project
4 * Original Author: Kasra Nassiri <cjax@users.sourceforge.net>
5 * Modified By: Joel Low <lowjoel@users.sourceforge.net>
6 * Modified By:
7 *
8 * This file is part of Eraser.
9 *
10 * Eraser is free software: you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free Software
12 * Foundation, either version 3 of the License, or (at your option) any later
13 * version.
14 *
15 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 *
19 * A copy of the GNU General Public License can be found at
20 * <http://www.gnu.org/licenses/>.
21 */
22
23using System;
24using System.IO;
25using System.Text;
26using System.IO.Pipes;
27using System.Threading;
28using System.Collections.Generic;
29
30using System.Runtime.Serialization;
31using System.Runtime.Remoting.Messaging;
32using System.Runtime.Serialization.Formatters.Binary;
33
34namespace Eraser.Manager
35{
[629]36    /// <summary>
37    /// Represents a request to the RemoteExecutorServer instance
38    /// </summary>
[627]39    [Serializable]
[629]40    internal class RemoteRequest
[627]41    {
[628]42        /// <summary>
43        /// List of supported functions
44        /// </summary>
[627]45        public enum Function : uint
46        {
[628]47            ADD_TASK = 0,
[627]48            GET_TASK,
49            GET_TASKS,
50            CANCEL_TASK,
51            DELETE_TASK,
52            QUEUE_TASK,
53            REPLACE_TASK,
54            SCHEDULE_TASK,
55            SAVE_TASK_LIST,
56            LOAD_TASK_LIST,
57            QUEUE_RESTART_TASK,
58        }
59
[628]60        /// <summary>
61        /// Constructor.
62        /// </summary>
63        /// <param name="func">The function this command is wanting to execute.</param>
64        /// <param name="data">The parameters for the command, serialised using a
65        /// BinaryFormatter</param>
[629]66        public RemoteRequest(Function func, byte[] data)
[628]67        {
68            Func = func;
69            Data = data;
70        }
71
[629]72        /// <summary>
73        /// The function that this request is meant to call.
74        /// </summary>
[627]75        public Function Func;
[629]76
77        /// <summary>
78        /// The parameters associated with the function call.
79        /// </summary>
[628]80        public byte[] Data;
[627]81    };
82
[629]83    /// <summary>
84    /// The RemoteExecutorServer class is the server half required for remote execution
85    /// of tasks.
86    /// </summary>
[610]87    public class RemoteExecutorServer : DirectExecutor
88    {
[629]89        /// <summary>
90        /// Our Remote Server name, prevent collisions!
91        /// </summary>
[738]92        public static readonly string ServerName =
93            "Eraser-FB6C5A7D-E47F-475f-ABA4-58F4D24BB67E-RemoteExecutor-" +
94            System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();
[610]95
[629]96        /// <summary>
97        /// The thread which will answer pipe connections
98        /// </summary>
[610]99        private Thread thread = null;
[629]100
101        /// <summary>
102        /// Our pipe instance which handles connections.
103        /// </summary>
[738]104        private NamedPipeServerStream server;
[610]105
[629]106        /// <summary>
107        /// Constructor.
108        /// </summary>
[610]109        public RemoteExecutorServer()
110        {
[738]111            server = new NamedPipeServerStream(ServerName, PipeDirection.InOut, 4,
112                PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
113
[610]114            thread = new Thread(Main);
115            thread.Start();
116            Thread.Sleep(0);
117        }
118
[627]119        public override void Dispose()
[610]120        {
[629]121            thread.Abort();
[628]122            base.Dispose();
[610]123        }
124
[629]125        /// <summary>
126        /// The polling loop dealing with every server connection.
127        /// </summary>
[610]128        private void Main()
129        {
130            while (Thread.CurrentThread.ThreadState != ThreadState.AbortRequested)
131            {
[630]132                //Wait for a connection to be established
133                if (!server.IsConnected)
134                {
135                    IAsyncResult asyncWait = server.BeginWaitForConnection(
136                        server.EndWaitForConnection, null);
137                    while (!server.IsConnected && !asyncWait.AsyncWaitHandle.WaitOne(15))
138                        if (Thread.CurrentThread.ThreadState == ThreadState.AbortRequested)
139                            break;
140                }
[628]141
142                //If we still aren't connected that means the connection failed to establish.
[615]143                if (!server.IsConnected)
[628]144                    continue;
[610]145
[628]146                //Read the request into the buffer.
[629]147                RemoteRequest request = null;
[628]148                using (MemoryStream mstream = new MemoryStream())
149                {
150                    byte[] buffer = new byte[65536];
151                    server.Read(buffer, 0, sizeof(int));
152                    int messageSize = BitConverter.ToInt32(buffer, 0);
153                    while (messageSize > 0)
154                    {
155                        int lastRead = server.Read(buffer, 0, Math.Min(messageSize, buffer.Length));
156                        messageSize -= lastRead;
157                        mstream.Write(buffer, 0, lastRead);
158                    }
[610]159
[628]160                    //Deserialise the header of the request.
161                    mstream.Position = 0;
[629]162                    request = (RemoteRequest)new BinaryFormatter().Deserialize(new MemoryStream(buffer));
[628]163                }
[610]164
[627]165                #region Deserialise
[630]166                object parameter = null;
[628]167                switch (request.Func)
[627]168                {
169                    // void \+ task
[629]170                    case RemoteRequest.Function.CANCEL_TASK:
171                    case RemoteRequest.Function.QUEUE_TASK:
172                    case RemoteRequest.Function.REPLACE_TASK:
173                    case RemoteRequest.Function.SCHEDULE_TASK:
174                    case RemoteRequest.Function.ADD_TASK:
[628]175                        using (MemoryStream mStream = new MemoryStream(request.Data))
[630]176                            parameter = new BinaryFormatter().Deserialize(mStream);
[627]177                        break;
[610]178
[627]179                    // bool \+ taskid
[629]180                    case RemoteRequest.Function.DELETE_TASK:
[627]181                    // task \+ taskid
[629]182                    case RemoteRequest.Function.GET_TASK:
[628]183                        using (MemoryStream mStream = new MemoryStream(request.Data))
[630]184                            parameter = new BinaryFormatter().Deserialize(mStream);
[627]185                        break;
[610]186
[627]187                    // void \+ stream
[629]188                    case RemoteRequest.Function.LOAD_TASK_LIST:
189                    case RemoteRequest.Function.SAVE_TASK_LIST:
[628]190                        using (MemoryStream mStream = new MemoryStream(request.Data))
[630]191                            parameter = new BinaryFormatter().Deserialize(mStream);
[627]192                        break;
[610]193
[627]194                    // list<task> \+ void
[629]195                    case RemoteRequest.Function.GET_TASKS:
[627]196                    // void \+ void
[629]197                    case RemoteRequest.Function.QUEUE_RESTART_TASK:
[627]198                        break;
[610]199
[627]200                    default:
201                        throw new FatalException("Unknown RemoteExecutorClient.Function");
202                }
203                #endregion
[610]204
[627]205                #region Invoke
[630]206                object returnValue = null;
[628]207                switch (request.Func)
[627]208                {
209                    // void \+ task
[629]210                    case RemoteRequest.Function.CANCEL_TASK:
[630]211                        CancelTask((Task)parameter);
[627]212                        break;
[610]213
[627]214                    // void \+ task
[629]215                    case RemoteRequest.Function.QUEUE_TASK:
[630]216                        QueueTask((Task)parameter);
[627]217                        break;
[610]218
[627]219                    // void \+ task
[629]220                    case RemoteRequest.Function.REPLACE_TASK:
[630]221                        ReplaceTask((Task)parameter);
[627]222                        break;
[610]223
[627]224                    // void \+ task
[629]225                    case RemoteRequest.Function.SCHEDULE_TASK:
[630]226                        ScheduleTask((Task)parameter);
[627]227                        break;
[610]228
[627]229                    // void \+ ref task
[629]230                    case RemoteRequest.Function.ADD_TASK:
[630]231                    {
232                        Task task = (Task)parameter;
[627]233                        AddTask(ref task);
234                        break;
[630]235                    }
[610]236
[627]237                    // bool \+ taskid
[629]238                    case RemoteRequest.Function.DELETE_TASK:
[630]239                        returnValue = DeleteTask((uint)parameter);
[627]240                        break;
[610]241
[627]242                    // task \+ taskid
[629]243                    case RemoteRequest.Function.GET_TASK:
[630]244                        returnValue = GetTask((uint)parameter);
[627]245                        break;
[610]246
[627]247                    // void \+ stream
[629]248                    case RemoteRequest.Function.LOAD_TASK_LIST:
[630]249                        LoadTaskList((Stream)parameter);
[627]250                        break;
[610]251
[627]252                    // void \+ stream
[629]253                    case RemoteRequest.Function.SAVE_TASK_LIST:
[630]254                        SaveTaskList((Stream)parameter);
[627]255                        break;
[610]256
[627]257                    // list<task> \+ void
[629]258                    case RemoteRequest.Function.GET_TASKS:
[627]259                        returnValue = GetTasks();
260                        break;
[610]261
[627]262                    // void \+ void
[629]263                    case RemoteRequest.Function.QUEUE_RESTART_TASK:
[627]264                        QueueRestartTasks();
265                        break;
[610]266
[627]267                    default:
268                        throw new FatalException("Unknown RemoteExecutorClient.Function");
[628]269                #endregion
[610]270                }
271
[630]272                //Return the result of the invoked function, if any.
273                if (returnValue != null)
274                    using (MemoryStream mStream = new MemoryStream())
275                    {
276                        new BinaryFormatter().Serialize(mStream, returnValue);
277                        byte[] buffer = mStream.ToArray();
278                        byte[] bufferLength = BitConverter.GetBytes(buffer.Length);
279                        server.Write(bufferLength, 0, sizeof(int));
280                        server.Write(buffer, 0, buffer.Length);
281                    }
282                else
[610]283                {
[630]284                    byte[] buffer = BitConverter.GetBytes(0);
285                    server.Write(buffer, 0, sizeof(int));
[610]286                }
287
288                // we are done, disconnect
289                server.Disconnect();
290            }
291        }
292    }
293
294    public class RemoteExecutorClient : Executor
295    {
[738]296        private NamedPipeClientStream client;
[610]297
298        public RemoteExecutorClient()
299        {
[738]300            client = new NamedPipeClientStream(".", RemoteExecutorServer.ServerName,
301                PipeDirection.InOut);
[610]302        }
303
304        public override void Dispose()
305        {
306            client.Close();
307            client.Dispose();
308        }
309
[737]310        /// <summary>
311        /// Connects to the remote server.
312        /// </summary>
313        /// <returns>True if the connection to the remote server was established.</returns>
314        public bool Connect()
315        {
316            try
317            {
318                client.Connect(250);
319            }
320            catch (TimeoutException)
321            {
322            }
323
324            return client.IsConnected;
325        }
326
[629]327        private object SendRequest(RemoteRequest header)
[610]328        {
[628]329            //Connect to the server
330            object result = null;
[619]331            client.Connect(5000);
[610]332
[628]333            using (MemoryStream mStream = new MemoryStream())
[610]334            {
[628]335                //Serialise the request
336                new BinaryFormatter().Serialize(mStream, header);
[610]337
[627]338                //Write the request to the pipe
[628]339                byte[] buffer = mStream.ToArray();
340                byte[] bufferLength = BitConverter.GetBytes(buffer.Length);
341                client.Write(bufferLength, 0, sizeof(int));
342                client.Write(buffer, 0, buffer.Length);
[610]343
[628]344                //Read the response from the pipe
345                mStream.Position = 0;
346                buffer = new byte[32768];
347                client.Read(buffer, 0, sizeof(int));
348                int responseLength = BitConverter.ToInt32(buffer, 0);
349                while (responseLength > 0)
350                    responseLength -= client.Read(buffer, 0, Math.Min(buffer.Length, responseLength));
351
[627]352                //Deserialise the response
[628]353                mStream.Position = 0;
[630]354                if (mStream.Length > 0)
355                    result = new BinaryFormatter().Deserialize(mStream);
[610]356            }
357
[628]358            return result;
[610]359        }
360
361        public override bool DeleteTask(uint taskId)
362        {
[628]363            MemoryStream mStream = new MemoryStream();
364            new BinaryFormatter().Serialize(mStream, taskId);
[629]365            return (bool)SendRequest(new RemoteRequest(RemoteRequest.Function.DELETE_TASK,
[628]366                mStream.GetBuffer()));
[610]367        }
368
369        public override List<Task> GetTasks()
370        {
[628]371            MemoryStream mStream = new MemoryStream();
372            new BinaryFormatter().Serialize(mStream, null);
[629]373            return (List<Task>)SendRequest(new RemoteRequest(RemoteRequest.Function.GET_TASKS,
[628]374                mStream.GetBuffer()));
[610]375        }
376
377        public override Task GetTask(uint taskId)
378        {
[628]379            MemoryStream mStream = new MemoryStream();
380            new BinaryFormatter().Serialize(mStream, taskId);
[629]381            return (Task)SendRequest(new RemoteRequest(RemoteRequest.Function.GET_TASK,
[628]382                mStream.GetBuffer()));
[610]383        }
384
385        public override void LoadTaskList(Stream stream)
386        {
[628]387            MemoryStream mStream = new MemoryStream();
388            new BinaryFormatter().Serialize(mStream, stream);
[629]389            SendRequest(new RemoteRequest(RemoteRequest.Function.LOAD_TASK_LIST,
[628]390                mStream.GetBuffer()));
[610]391        }
392
393        public override void AddTask(ref Task task)
394        {
[628]395            MemoryStream mStream = new MemoryStream();
396            new BinaryFormatter().Serialize(mStream, task);
[629]397            SendRequest(new RemoteRequest(RemoteRequest.Function.ADD_TASK,
[628]398                mStream.GetBuffer()));
[610]399        }
400
401        public override void CancelTask(Task task)
402        {
[628]403            MemoryStream mStream = new MemoryStream();
404            new BinaryFormatter().Serialize(mStream, task);
[629]405            SendRequest(new RemoteRequest(RemoteRequest.Function.CANCEL_TASK,
[628]406                mStream.GetBuffer()));
[610]407        }
408
409        public override void QueueRestartTasks()
410        {
[628]411            MemoryStream mStream = new MemoryStream();
412            new BinaryFormatter().Serialize(mStream, null);
[629]413            SendRequest(new RemoteRequest(RemoteRequest.Function.QUEUE_RESTART_TASK,
[628]414                mStream.GetBuffer()));
[610]415        }
416
417        public override void QueueTask(Task task)
418        {
[628]419            MemoryStream mStream = new MemoryStream();
420            new BinaryFormatter().Serialize(mStream, task);
[629]421            SendRequest(new RemoteRequest(RemoteRequest.Function.QUEUE_TASK,
[628]422                mStream.GetBuffer()));
[610]423        }
424
425        public override void ReplaceTask(Task task)
426        {
[628]427            MemoryStream mStream = new MemoryStream();
428            new BinaryFormatter().Serialize(mStream, task);
[629]429            SendRequest(new RemoteRequest(RemoteRequest.Function.REPLACE_TASK,
[628]430                mStream.GetBuffer()));
[610]431        }
432
433        public override void Run()
434        {
435        }
436
437        public override void ScheduleTask(Task task)
438        {
[628]439            MemoryStream mStream = new MemoryStream();
440            new BinaryFormatter().Serialize(mStream, task);
[629]441            SendRequest(new RemoteRequest(RemoteRequest.Function.SCHEDULE_TASK,
[628]442                mStream.GetBuffer()));
[610]443        }
444
445        public override void SaveTaskList(Stream stream)
446        {
[628]447            MemoryStream mStream = new MemoryStream();
448            new BinaryFormatter().Serialize(mStream, stream);
[629]449            SendRequest(new RemoteRequest(RemoteRequest.Function.SAVE_TASK_LIST,
[628]450                mStream.GetBuffer()));
[610]451        }
452    }
[628]453}
Note: See TracBrowser for help on using the repository browser.