Esempio n. 1
0
 public void Start()
 {
     lock (Console.Out)
     {
         _dbm            = DBManagerFactory.NewManager();
         _timer          = new Timer();
         _startTime      = DateTime.Now;
         _pathsCompleted = 0;
         _timer.Elapsed += new ElapsedEventHandler(Run);
         _timer.Interval = 1000;
         _timer.Enabled  = true;
     }
 }
Esempio n. 2
0
            // This is the method executed by the thread. It will manage the interaction with the guest process, sending commands and receiving informations about the Intaller UI and logging system.
            private void Run()
            {
                #region Declaration and initializations
                _status  = NetworkWorkerStatus.Busy;
                _dbm     = DBManagerFactory.NewManager();
                _noLoop  = new List <string>();
                _mainJob = null;
                _todoJob = null;
                string followedPath = null;
                _followedPathBitmaps = new List <string>();
                string remoteIp   = ((IPEndPoint)_socket.Client.RemoteEndPoint).Address.ToString();
                int    remotePort = ((IPEndPoint)_socket.Client.RemoteEndPoint).Port;
                #endregion


                /*------------------------------------------------------------
                 *
                 *                          PHASE 1
                 *         Retrive job from DB and send it to the guest.
                 *
                 * -----------------------------------------------------------
                 */
                try
                {
                    #region First Setp: Get The Job from the DB and send it to the remote guest

                    /*-----------------------------------------------------------
                     * ----------------------------------------------------------
                     *         Get the Job from the DB and send it to the Guest
                     * ----------------------------------------------------------
                     * ----------------------------------------------------------*/
                    while (_todoJob == null)
                    {
                        // Now the machine will send a Request every minute to get more work. Expect it!
                        ReceiveCallForWork();

                        lock (_lock)
                        {
                            _todoJob = _dbm.PopTodoJob(out _mainJob);
                        }

                        if (_mainJob == null)
                        {
                            // There's nothing to do... wait please!
                            SendNoJobs();
                            Log("No jobs found for that worker...");
                            Log("Worker thread started with guest " + ((IPEndPoint)_socket.Client.RemoteEndPoint).Address + ":" + ((IPEndPoint)_socket.Client.RemoteEndPoint).Port);
                            _status = NetworkWorkerStatus.Ready;
                        }
                        else
                        {
                            SendWorkReady();
                            // Now the loop will stop
                            // break;
                        }
                    }


                    // Send Work to the remote guest
                    Log("Sending work to remote guest: MAINJOIB ID " + _mainJob.Id + " (" + _mainJob.InstallerPath + "), TODOJOB ID " + _todoJob.Id + " (" + _todoJob.ActionPath + ").");
                    SendWork();

                    // Wait for ACK, meaning Process started correctly
                    Log("Waiting for remote process start");
                    ReceiveAck();
                    Log("Remote process started");

                    //Stats.Instance.notifyWork((IPEndPoint)_socket.Client.RemoteEndPoint,_mainJob,_todoJob);

                    #endregion
                }
                catch (Exception e) // Error handling for phase 1
                {
                    // In case of exception, if any job has been retrived,
                    // remove it from TODO-Table and move it to the done table.
                    // Add error logs both to the local log and to the XML logfile in the DONE table.
                    #region Error handling for phase 1
                    // The job has been popped from db.
                    // Log the error locally
                    Logger.Instance.logError("Unhandled exception in Worker Manager in phase 1. TodoJob ID = " + _todoJob.Id, e);
                    Log("Unhandled exception in Worker Manager in phase 1. TodoJob ID = " + _todoJob.Id + "\n" + e.Message + "\n" + e.StackTrace);
                    // Log it into the db
                    string xmlErrorLog = BuildHostXmlError("Unhandled exception in Worker Manager in phase 1", e, _todoJob, _mainJob, _vmName, followedPath);
                    if (_todoJob != null)
                    {
                        // Set that job as done
                        _dbm.InsertDoneWithError(NetworkProtocol.Protocol.URI_APP_START, _mainJob, xmlErrorLog);
                        // Now delete the todo job from the db
                        _dbm.DeleteTodoJob(_todoJob);
                    }

                    // Finally revert the VM
                    VMManager.Instance.RevertVm(_vmName);

                    // Clear stuff and return
                    _dbm.Dispose();
                    _sReader.Close();
                    _sWriter.Close();
                    _socket.Close();

                    return;

                    #endregion
                }


                /*------------------------------------------------------------
                 *
                 *                          PHASE 2
                 *         Following the stored path of the current todojob.
                 *
                 * -----------------------------------------------------------
                 */
                followedPath = Protocol.URI_APP_START;
                try
                {
                    #region Second Step: interact with UI until FollowedPath == todojob.FullPath

                    Log("Following path: " + _todoJob.ActionPath);
                    while (followedPath != _todoJob.ActionPath)
                    {
                        // 1. Check that remote process is running
                        Log("Receiving process status");
                        Int16 procStatus = ReceiveProcessStatus();
                        if (procStatus != Protocol.PROCESS_GOING)
                        {
                            // This is unespected, so throw an exception
                            throw new ProtocolException("Error during path following: The remote process is not running.");
                        }
                        Log("Receiving possible interactions");
                        // 2. Receive the list of possible interaction to perform with the UI
                        PossibleInteraction res = ReceivePossibleInteractions();

                        // 3. Check if the window has been already scanned: if yes, throw an exception, otherwise add the hash to the scanned windows list
                        if (_noLoop.Contains(res.winStatusHash))
                        {
                            throw new LoopException();
                        }
                        else
                        {
                            _noLoop.Add(res.winStatusHash);
                        }

                        // 4. Check if the next action to perform is into the list of the actions received by the Guest
                        TodoJob.Action next = _todoJob.NextAction();

                        /*
                         * bool controlFound = false;
                         * bool interactionFound = false;
                         * for (int i = 0; i < res.ids.Length; i++)
                         * {
                         *  if (next.controlId == res.ids[i])
                         *  {
                         *      controlFound = true;
                         *      for (int j = 0; j < res.interactions[i].Length; j++)
                         *      {
                         *          if (res.interactions[i][j] == next.interactionType)
                         *          {
                         *              interactionFound = true;
                         *              break;
                         *          }
                         *      }
                         *      break;
                         *  }
                         * }
                         * if (!interactionFound)
                         * {
                         *  Log("Cannot follow the written path. The control I was looking for is absent.");
                         *  // The interaction we were looking for is not present into the collection received by the guest. Throw an exception then!
                         *  if (!controlFound)
                         *      throw new InconsistentPathException("Error: inconsistent path. The guest has no control ID " + next.controlId);
                         *  else
                         *      throw new InconsistentPathException("Error: inconsistent path. The control ID " + next.controlId + " doesn't allow interactiontype " + next.interactionType);
                         * }
                         */
                        // 5. Execute the interaction
                        Log("Executing interaction...");
                        if (SendCommand(next.controlId, next.interactionType))
                        {
                            // Mark the choosen element
                            int id = -1;
                            for (int i = 0; i < res.ids.Length; i++)
                            {
                                if (next.controlId == res.ids[i])
                                {
                                    id = i;
                                    break;
                                }
                            }
                            if (id == -1)
                            {
                                throw new ApplicationException("Inconsistency error: no control id found within the RES array.");
                            }
                            DrawAndStoreBitmap(res.bitmap, (int)res.topLeftX[id], (int)res.topLeftY[id], (int)(res.bottomRightX[id] - res.topLeftX[id]), (int)(res.topLeftY[id] - res.bottomRightY[id]));
                            // Everything is good, update the path
                            followedPath += next.relativePath + Protocol.URI_PATH_SEP;
                            Log("Interaction completed succesfully. New path is: " + followedPath);
                        }
                        else
                        {
                            throw new GuestCommandFailedException("Guest reported a problem when executing the action " + next.controlId + "=" + next.interactionType);
                        }
                    }
                    #endregion
                }
                catch (Exception e)
                {
                    // If a loop is detected, save the path in DONE table with an appropriate error message. Then remove that TODO entry and all the others
                    // starting like that from the TODO table. After that,simply ask the remote guest to reboot.
                    #region Error Handling for phase 2
                    Log("Loop exception catched during Pahse 2.");
                    string xmlError = BuildHostXmlError("Loop detected during phase 2.", e, _todoJob, _mainJob, _vmName, followedPath);
                    Log("Inserting done job to the DB");
                    _dbm.InsertDoneWithError(NetworkProtocol.Protocol.URI_APP_START, _mainJob, xmlError);
                    Log("Deleting todojob starting with: " + followedPath);
                    _dbm.DeleteTodoJobsStartingWithPath(followedPath);
                    Log("Deleting this todojob: " + _todoJob.ActionPath);
                    _dbm.DeleteTodoJob(_todoJob);
                    Log("Reverting VM...");
                    VMManager.Instance.RevertVm(_vmName);
                    Stats.Instance.notifyLoop();
                    Log("Clearing resources and returning.");
                    _sReader.Close();
                    _sWriter.Close();
                    _socket.Close();
                    _dbm.Dispose();
                    Log("Returning.");
                    return;

                    #endregion
                }


                /*------------------------------------------------------------
                 *
                 *                          PHASE 3
                 *                      Discovering paths
                 *
                 * -----------------------------------------------------------
                 */
                try
                {
                    #region Phase 3: interact with the UI until the remtoe process is running
                    Int16 guestStatus;
                    Log("Path completely followed, now it begins path discovery.");
                    while ((guestStatus = ReceiveProcessStatus()) == Protocol.PROCESS_GOING)
                    {
                        Log("Process status RUNNING received.");
                        // 1. Receive all possible interactions. This means also the Window has will be received.
                        Log("Getting possible interactions...");
                        PossibleInteraction res = ReceivePossibleInteractions();

                        // 2. Check the window hash: if it is already present into the noLoop array, throw a loop exception. Otherwise simply add the has to that array
                        if (_noLoop.Contains(res.winStatusHash))
                        {
                            throw new LoopException();
                        }
                        else
                        {
                            _noLoop.Add(res.winStatusHash);
                        }

                        // 3. Now filter all the possible interactions received. Must delete all the already done actions (DONE TABLE), all the ones which are already present into the TODO table.
                        List <string> allPossibleInteractions = BuildPaths(followedPath, res);
                        List <string> toDo = _dbm.FilterDoneOrTodoByPath(allPossibleInteractions);

                        Log("Discovered " + toDo.Count + " new paths.");
                        if (toDo.Count == 0)
                        {
                            Log("I don't know what to do next!!!!!!!!");
                            // There's nothing to do next: Reboot the guest
                            _dbm.DeleteTodoJob(_todoJob);
                            VMManager.Instance.RevertVm(_vmName);
                            //throw new NotSupportedException("Check this: should I add this done path to the DB?");
                            // I guess I should break in that case, collect info and reboot the remote guest
                            // break;
                        }
                        else
                        {
                            // 4. Pop one of the actions filtered and save the others into the TODO table
                            string fullPathToPerform = toDo.First(); // Copied or not?
                            toDo.RemoveAt(0);                        // Now is fullPathToPerform still valid?
                            foreach (string s in toDo)
                            {
                                _dbm.InsertAction(_mainJob.Id, s);
                            }
                            // Now proceed with the choosen one
                            string tmp   = fullPathToPerform.Split(new string[] { Protocol.URI_PATH_SEP }, StringSplitOptions.RemoveEmptyEntries).Last();
                            string cId   = tmp.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[0];
                            int    cType = int.Parse(tmp.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries)[1]);
                            Log("Saved all the others command to the DB. I'bve choosen the following: " + cId + "=" + cType);
                            if (!SendCommand(cId, cType))
                            {
                                Log("Error during remote command execution... command failed.");
                                throw new GuestCommandFailedException("The guest failed executing command " + cId + "=" + cType);
                            }
                            else
                            {
                                // Mark the choosen element
                                int id = -1;
                                for (int i = 0; i < res.ids.Length; i++)
                                {
                                    if (cId == res.ids[i])
                                    {
                                        id = i;
                                        break;
                                    }
                                }
                                if (id == -1)
                                {
                                    throw new ApplicationException("Inconsistency error: no control id found within the RES array.");
                                }
                                DrawAndStoreBitmap(res.bitmap, (int)(res.topLeftX[id]), (int)res.topLeftY[id], (int)(res.bottomRightX[id] - res.topLeftX[id]), (int)(res.bottomRightY[id] - res.topLeftY[id]));
                                followedPath += cId + "=" + cType + Protocol.URI_PATH_SEP;
                                Log("Command executed. the remote path is " + followedPath);
                            }
                        }
                    }
                    #endregion
                }
                catch (GuestCommandFailedException e)
                {
                    #region Error handling
                    Log("Error during phase 3: Remote Guest has reported a command execution failure.");
                    string xmlErrorLog = BuildHostXmlError("Error during phase 3: Remote Guest has reported a command execution failure.", e, _todoJob, _mainJob, _vmName, followedPath);
                    Log("Inserting done job to the DB");
                    _dbm.InsertDoneWithError(followedPath, _mainJob, xmlErrorLog);
                    Log("Deleting similar branches from db");
                    _dbm.DeleteTodoJobsStartingWithPath(followedPath);
                    Log("Freeing resources");
                    _sWriter.Close();
                    _sReader.Close();
                    _socket.Close();
                    _dbm.Dispose();
                    Log("Reverting VM");
                    //_fileLogger.Close();
                    VMManager.Instance.RevertVm(_vmName);
                    return;

                    #endregion
                }
                catch (LoopException e)
                {
                    #region Error Handling
                    Log("Error during phase 3: Loop detected.");
                    string xmlErrorLog = BuildHostXmlError("Error during phase 3: Loop detected.", e, _todoJob, _mainJob, _vmName, followedPath);
                    Log("Inserting done job to the DB");
                    _dbm.InsertDoneWithError(followedPath, _mainJob, xmlErrorLog);
                    Log("Deleting similar branches from db");
                    _dbm.DeleteTodoJobsStartingWithPath(followedPath);
                    Log("Freeing resources");
                    _sWriter.Close();
                    _sReader.Close();
                    _socket.Close();
                    _dbm.Dispose();
                    Stats.Instance.notifyLoop();
                    Log("Reverting VM");
                    //_fileLogger.Close();
                    VMManager.Instance.RevertVm(_vmName);
                    Log("Returning.");
                    return;

                    #endregion
                }
                catch (Exception e)
                {
                    #region Error Handling
                    Log("Unhandled Exception during phase 3. \n" + e.Message + "\n" + e.StackTrace);
                    string xmlErrorLog = BuildHostXmlError("Unhandled Exception during phase 3.", e, _todoJob, _mainJob, _vmName, followedPath);
                    Log("Inserting done job to the DB");
                    _dbm.InsertDoneWithError(followedPath, _mainJob, xmlErrorLog);
                    Log("Deleting similar branches from db");
                    _dbm.DeleteTodoJobsStartingWithPath(followedPath);
                    Log("Freeing resources");
                    _sWriter.Close();
                    _sReader.Close();
                    _socket.Close();
                    _dbm.Dispose();
                    Log("Reverting VM");
                    //_fileLogger.Close();
                    VMManager.Instance.RevertVm(_vmName);
                    return;

                    #endregion
                }


                /*------------------------------------------------------------
                 *
                 *                          PHASE 4
                 *     Collet info about the program which has just exited
                 *
                 * -----------------------------------------------------------
                 */
                try
                {
                    #region Phase 4: collect info about remote guest
                    Log("Remote Guest has exited. Collecting information.");
                    Log("Receiving xml info...");
                    XmlDocument xmlInfo = ReceiveMachineInfo();
                    XmlElement  uisteps = xmlInfo.CreateElement("UISteps");
                    for (int i = 0; i < _followedPathBitmaps.Count; i++)
                    {
                        XmlElement el = xmlInfo.CreateElement("STEP");
                        el.SetAttribute("ID", "" + i);
                        el.InnerText = _followedPathBitmaps[i];
                        uisteps.AppendChild(el);
                    }
                    xmlInfo.GetElementsByTagName("ROOT")[0].AppendChild(uisteps);

                    // Create the file on the REPORTS folder
                    Log("Saving report...");
                    string reportPath = SaveReport(xmlInfo, _mainJob, _todoJob);
                    Log("Updating db...");
                    _dbm.InsertDone(followedPath, _mainJob, reportPath);
                    _dbm.DeleteTodoJob(_todoJob);
                    Log("Rebooting guest...");

                    // Read the ACK from guest: is that a VM or not?
                    Int16 ans = _sReader.ReadInt16();
                    if (ans == Protocol.ACK_REMOTE_REBOOT)
                    {
                        // It is a VM, so reboot it
                        string vmName = _sReader.ReadString();
                        // reboot moved to finally block //fixme, i'm ugly!
                    }
                    else if (ans == Protocol.ACK_LOCAL_REBOOT)
                    {
                        throw new NotSupportedException("Bare metal support isn't available yet.");
                    }
                    else
                    {
                        throw new ProtocolException("Error: i was expecting an ACK for REMTOEREBOOT or LOCALREBOOT. I received " + ans + " instead.");
                    }
                    #endregion
                }
                catch (Exception e)
                {
                    #region Error handling
                    Log("Unhandled error during phase 4.\n" + e.Message + "\n" + e.StackTrace);
                    string xmlErrorLog = BuildHostXmlError("Unhandled error during phase 4.", e, _todoJob, _mainJob, _vmName, followedPath);
                    Log("Inserting done job to the DB");
                    _dbm.InsertDoneWithError(followedPath, _mainJob, xmlErrorLog);
                    Log("Deleting similar branches from db");
                    _dbm.DeleteTodoJobsStartingWithPath(followedPath);
                    #endregion
                }
                finally
                {
                    #region Final resource cleaning
                    _sReader.Close();
                    _sWriter.Close();
                    _socket.Close();
                    Log("Cleaning resourced for this thread and exiting.");
                    //_fileLogger.Dispose();
                    _dbm.Dispose();
                    Stats.Instance.notifyCompletedPath();
                    VMManager.Instance.RevertVm(_vmName);
                    #endregion
                }

                return;
            }