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

Revision 927, 12.4 KB checked in by lowjoel, 5 years ago (diff)

Accidental commit, sorry.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
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.Text;
25using System.IO;
26using System.IO.Pipes;
27using System.Threading;
28using System.Collections.Generic;
29
30using System.Runtime.Serialization;
31using System.Runtime.Serialization.Formatters.Binary;
32
33namespace Eraser.Manager
34{
35    /// <summary>
36    /// Represents a request to the RemoteExecutorServer instance
37    /// </summary>
38    [Serializable]
39    internal class RemoteRequest
40    {
41        /// <summary>
42        /// List of supported functions
43        /// </summary>
44        public enum Function : uint
45        {
46            ADD_TASK = 0,
47            GET_TASK,
48            GET_TASKS,
49            CANCEL_TASK,
50            DELETE_TASK,
51            QUEUE_TASK,
52            REPLACE_TASK,
53            SCHEDULE_TASK,
54            SAVE_TASK_LIST,
55            LOAD_TASK_LIST,
56            QUEUE_RESTART_TASK,
57        }
58
59        /// <summary>
60        /// Constructor.
61        /// </summary>
62        /// <param name="func">The function this command is wanting to execute.</param>
63        /// <param name="data">The parameters for the command, serialised using a
64        /// BinaryFormatter</param>
65        public RemoteRequest(Function func, byte[] data)
66        {
67            Func = func;
68            Data = data;
69        }
70
71        /// <summary>
72        /// The function that this request is meant to call.
73        /// </summary>
74        public Function Func;
75
76        /// <summary>
77        /// The parameters associated with the function call.
78        /// </summary>
79        public byte[] Data;
80    };
81
82    /// <summary>
83    /// The RemoteExecutorServer class is the server half required for remote execution
84    /// of tasks.
85    /// </summary>
86    public class RemoteExecutorServer : DirectExecutor
87    {
88        /// <summary>
89        /// Our Remote Server name, prevent collisions!
90        /// </summary>
91        public static readonly string ServerName =
92            "Eraser-FB6C5A7D-E47F-475f-ABA4-58F4D24BB67E-RemoteExecutor-" +
93            System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();
94
95        /// <summary>
96        /// The thread which will answer pipe connections
97        /// </summary>
98        private Thread thread;
99
100        /// <summary>
101        /// Constructor.
102        /// </summary>
103        public RemoteExecutorServer()
104        {
105            thread = new Thread(Main);
106            thread.Start();
107            Thread.Sleep(0);
108        }
109
110        protected override void Dispose(bool disposing)
111        {
112            thread.Abort();
113            base.Dispose(disposing);
114        }
115
116        /// <summary>
117        /// The polling loop dealing with every server connection.
118        /// </summary>
119        private void Main()
120        {
121            while (Thread.CurrentThread.ThreadState != ThreadState.AbortRequested)
122            {
123                //Wait for a connection to be established
124                NamedPipeServerStream server = new NamedPipeServerStream(ServerName,
125                    PipeDirection.InOut, 4, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
126                IAsyncResult asyncWait = server.BeginWaitForConnection(
127                    EndWaitForConnection, server);
128
129                //Wait for a connection before moving on to create another listening server
130                asyncWait.AsyncWaitHandle.WaitOne();
131            }
132        }
133
134        /// <summary>
135        /// Waits for a connection from a client.
136        /// </summary>
137        /// <param name="result">The AsyncResult object associated with this asynchronous
138        /// operation.</param>
139        private void EndWaitForConnection(IAsyncResult result)
140        {
141            using (NamedPipeServerStream server = (NamedPipeServerStream)result.AsyncState)
142            {
143                //We're done waiting for the connection
144                server.EndWaitForConnection(result);
145
146                //Read the request into the buffer.
147                RemoteRequest request = null;
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                    }
159
160                    //Ignore the request if the client disconnected from us.
161                    if (!server.IsConnected)
162                        return;
163
164                    //Deserialise the header of the request.
165                    mstream.Position = 0;
166                    try
167                    {
168                        request = (RemoteRequest)new BinaryFormatter().Deserialize(
169                            new MemoryStream(buffer));
170                    }
171                    catch (SerializationException)
172                    {
173                        //We got a unserialisation issue but we can't do anything about it.
174                        return;
175                    }
176                }
177
178                #region Deserialise
179                object parameter = null;
180                switch (request.Func)
181                {
182                    // void \+ task
183                    case RemoteRequest.Function.CANCEL_TASK:
184                    case RemoteRequest.Function.QUEUE_TASK:
185                    case RemoteRequest.Function.REPLACE_TASK:
186                    case RemoteRequest.Function.SCHEDULE_TASK:
187                    case RemoteRequest.Function.ADD_TASK:
188                        using (MemoryStream mStream = new MemoryStream(request.Data))
189                            parameter = new BinaryFormatter().Deserialize(mStream);
190                        break;
191
192                    // bool \+ taskid
193                    case RemoteRequest.Function.DELETE_TASK:
194                    // task \+ taskid
195                    case RemoteRequest.Function.GET_TASK:
196                        using (MemoryStream mStream = new MemoryStream(request.Data))
197                            parameter = new BinaryFormatter().Deserialize(mStream);
198                        break;
199
200                    // void \+ stream
201                    case RemoteRequest.Function.LOAD_TASK_LIST:
202                    case RemoteRequest.Function.SAVE_TASK_LIST:
203                        using (MemoryStream mStream = new MemoryStream(request.Data))
204                            parameter = new BinaryFormatter().Deserialize(mStream);
205                        break;
206
207                    // list<task> \+ void
208                    case RemoteRequest.Function.GET_TASKS:
209                    // void \+ void
210                    case RemoteRequest.Function.QUEUE_RESTART_TASK:
211                        break;
212
213                    default:
214                        throw new FatalException("Unknown RemoteExecutorClient.Function");
215                }
216                #endregion
217
218                #region Invoke
219                object returnValue = null;
220                switch (request.Func)
221                {
222                    // void \+ task
223                    case RemoteRequest.Function.CANCEL_TASK:
224                        CancelTask((Task)parameter);
225                        break;
226
227                    // void \+ task
228                    case RemoteRequest.Function.QUEUE_TASK:
229                        QueueTask((Task)parameter);
230                        break;
231
232                    // void \+ task
233                    case RemoteRequest.Function.REPLACE_TASK:
234                        ReplaceTask((Task)parameter);
235                        break;
236
237                    // void \+ task
238                    case RemoteRequest.Function.SCHEDULE_TASK:
239                        ScheduleTask((Task)parameter);
240                        break;
241
242                    // void \+ ref task
243                    case RemoteRequest.Function.ADD_TASK:
244                        {
245                            Task task = (Task)parameter;
246                            AddTask(task);
247                            break;
248                        }
249
250                    // bool \+ taskid
251                    case RemoteRequest.Function.DELETE_TASK:
252                        returnValue = DeleteTask((uint)parameter);
253                        break;
254
255                    // task \+ taskid
256                    case RemoteRequest.Function.GET_TASK:
257                        returnValue = GetTask((uint)parameter);
258                        break;
259
260                    // void \+ stream
261                    case RemoteRequest.Function.LOAD_TASK_LIST:
262                        LoadTaskList((Stream)parameter);
263                        break;
264
265                    // void \+ stream
266                    case RemoteRequest.Function.SAVE_TASK_LIST:
267                        SaveTaskList((Stream)parameter);
268                        break;
269
270                    // list<task> \+ void
271                    case RemoteRequest.Function.GET_TASKS:
272                        returnValue = GetTasks();
273                        break;
274
275                    // void \+ void
276                    case RemoteRequest.Function.QUEUE_RESTART_TASK:
277                        QueueRestartTasks();
278                        break;
279
280                    default:
281                        throw new FatalException("Unknown RemoteExecutorClient.Function");
282                }
283                #endregion
284
285                //Return the result of the invoked function, if any.
286                if (returnValue != null)
287                    using (MemoryStream mStream = new MemoryStream())
288                    {
289                        new BinaryFormatter().Serialize(mStream, returnValue);
290                        byte[] buffer = mStream.ToArray();
291                        byte[] bufferLength = BitConverter.GetBytes(buffer.Length);
292                        server.Write(bufferLength, 0, sizeof(int));
293                        server.Write(buffer, 0, buffer.Length);
294                    }
295                else
296                {
297                    byte[] buffer = BitConverter.GetBytes(0);
298                    server.Write(buffer, 0, sizeof(int));
299                }
300            }
301        }
302    }
303
304    public class RemoteExecutorClient : Executor
305    {
306        private NamedPipeClientStream client;
307
308        public RemoteExecutorClient()
309        {
310            client = new NamedPipeClientStream(".", RemoteExecutorServer.ServerName,
311                PipeDirection.InOut);
312        }
313
314        protected override void Dispose(bool disposing)
315        {
316            client.Close();
317            client.Dispose();
318            base.Dispose(disposing);
319        }
320
321        /// <summary>
322        /// Connects to the remote server.
323        /// </summary>
324        /// <returns>True if the connection to the remote server was established.</returns>
325        public bool Connect()
326        {
327            try
328            {
329                client.Connect(3000);
330            }
331            catch (TimeoutException)
332            {
333            }
334
335            return client.IsConnected;
336        }
337
338        private object SendRequest(RemoteRequest header)
339        {
340            //Connect to the server
341            object result = null;
342
343            using (MemoryStream mStream = new MemoryStream())
344            {
345                //Serialise the request
346                new BinaryFormatter().Serialize(mStream, header);
347
348                //Write the request to the pipe
349                byte[] buffer = mStream.ToArray();
350                byte[] bufferLength = BitConverter.GetBytes(buffer.Length);
351                client.Write(bufferLength, 0, sizeof(int));
352                client.Write(buffer, 0, buffer.Length);
353
354                //Read the response from the pipe
355                mStream.Position = 0;
356                buffer = new byte[32768];
357                client.Read(buffer, 0, sizeof(int));
358                int responseLength = BitConverter.ToInt32(buffer, 0);
359                while (responseLength > 0)
360                    responseLength -= client.Read(buffer, 0, Math.Min(buffer.Length, responseLength));
361
362                //Deserialise the response
363                mStream.Position = 0;
364                if (mStream.Length > 0)
365                    result = new BinaryFormatter().Deserialize(mStream);
366            }
367
368            return result;
369        }
370
371        public override bool DeleteTask(uint taskId)
372        {
373            MemoryStream mStream = new MemoryStream();
374            new BinaryFormatter().Serialize(mStream, taskId);
375            return (bool)SendRequest(new RemoteRequest(RemoteRequest.Function.DELETE_TASK,
376                mStream.GetBuffer()));
377        }
378
379        public override ICollection<Task> GetTasks()
380        {
381            MemoryStream mStream = new MemoryStream();
382            new BinaryFormatter().Serialize(mStream, null);
383            return (List<Task>)SendRequest(new RemoteRequest(RemoteRequest.Function.GET_TASKS,
384                mStream.GetBuffer()));
385        }
386
387        public override Task GetTask(uint taskId)
388        {
389            MemoryStream mStream = new MemoryStream();
390            new BinaryFormatter().Serialize(mStream, taskId);
391            return (Task)SendRequest(new RemoteRequest(RemoteRequest.Function.GET_TASK,
392                mStream.GetBuffer()));
393        }
394
395        public override void LoadTaskList(Stream stream)
396        {
397            MemoryStream mStream = new MemoryStream();
398            new BinaryFormatter().Serialize(mStream, stream);
399            SendRequest(new RemoteRequest(RemoteRequest.Function.LOAD_TASK_LIST,
400                mStream.GetBuffer()));
401        }
402
403        public override void AddTask(Task task)
404        {
405            MemoryStream mStream = new MemoryStream();
406            new BinaryFormatter().Serialize(mStream, task);
407            SendRequest(new RemoteRequest(RemoteRequest.Function.ADD_TASK,
408                mStream.GetBuffer()));
409        }
410
411        public override void CancelTask(Task task)
412        {
413            MemoryStream mStream = new MemoryStream();
414            new BinaryFormatter().Serialize(mStream, task);
415            SendRequest(new RemoteRequest(RemoteRequest.Function.CANCEL_TASK,
416                mStream.GetBuffer()));
417        }
418
419        public override void QueueRestartTasks()
420        {
421            MemoryStream mStream = new MemoryStream();
422            new BinaryFormatter().Serialize(mStream, null);
423            SendRequest(new RemoteRequest(RemoteRequest.Function.QUEUE_RESTART_TASK,
424                mStream.GetBuffer()));
425        }
426
427        public override void QueueTask(Task task)
428        {
429            MemoryStream mStream = new MemoryStream();
430            new BinaryFormatter().Serialize(mStream, task);
431            SendRequest(new RemoteRequest(RemoteRequest.Function.QUEUE_TASK,
432                mStream.GetBuffer()));
433        }
434
435        public override void ReplaceTask(Task task)
436        {
437            MemoryStream mStream = new MemoryStream();
438            new BinaryFormatter().Serialize(mStream, task);
439            SendRequest(new RemoteRequest(RemoteRequest.Function.REPLACE_TASK,
440                mStream.GetBuffer()));
441        }
442
443        public override void Run()
444        {
445        }
446
447        public override void ScheduleTask(Task task)
448        {
449            MemoryStream mStream = new MemoryStream();
450            new BinaryFormatter().Serialize(mStream, task);
451            SendRequest(new RemoteRequest(RemoteRequest.Function.SCHEDULE_TASK,
452                mStream.GetBuffer()));
453        }
454
455        public override void SaveTaskList(Stream stream)
456        {
457            MemoryStream mStream = new MemoryStream();
458            new BinaryFormatter().Serialize(mStream, stream);
459            SendRequest(new RemoteRequest(RemoteRequest.Function.SAVE_TASK_LIST,
460                mStream.GetBuffer()));
461        }
462    }
463}
Note: See TracBrowser for help on using the repository browser.