// -*- mode: cpp; mode: fold -*-
// Description /*{{{*/
/* ######################################################################
Acquire Worker - Worker process manager
Each worker class is associated with exaclty one subprocess.
##################################################################### */
/*}}}*/
/** \addtogroup acquire
* @{
*
* \file acquire-worker.h
*/
#ifndef PKGLIB_ACQUIRE_WORKER_H
#define PKGLIB_ACQUIRE_WORKER_H
#include <apt-pkg/acquire.h>
#include <apt-pkg/weakptr.h>
#include <sys/types.h>
#include <string>
#include <vector>
/** \brief A fetch subprocess.
*
* A worker process is responsible for one stage of the fetch. This
* class encapsulates the communications protocol between the master
* process and the worker, from the master end.
*
* Each worker is intrinsically placed on two linked lists. The
* Queue list (maintained in the #NextQueue variable) is maintained
* by the pkgAcquire::Queue class; it represents the set of workers
* assigned to a particular queue. The Acquire list (maintained in
* the #NextAcquire variable) is maintained by the pkgAcquire class;
* it represents the set of active workers for a particular
* pkgAcquire object.
*
* \todo Like everything else in the Acquire system, this has way too
* many protected items.
*
* \sa pkgAcqMethod, pkgAcquire::Item, pkgAcquire
*/
class pkgAcquire::Worker : public WeakPointable
{
/** \brief dpointer placeholder (for later in case we need it) */
void * const d;
friend class pkgAcquire;
protected:
friend class Queue;
/** \brief The next link on the Queue list.
*
* \todo This is always NULL; is it just for future use?
*/
Worker *NextQueue;
/** \brief The next link on the Acquire list. */
Worker *NextAcquire;
/** \brief The Queue with which this worker is associated. */
Queue *OwnerQ;
/** \brief The download progress indicator to which progress
* messages should be sent.
*/
pkgAcquireStatus *Log;
/** \brief The configuration of this method. On startup, the
* target of this pointer is filled in with basic data about the
* method, as reported by the worker.
*/
MethodConfig *Config;
/** \brief The access method to be used by this worker.
*
* \todo Doesn't this duplicate Config->Access?
*/
std::string Access;
/** \brief The PID of the subprocess. */
pid_t Process;
/** \brief A file descriptor connected to the standard output of
* the subprocess.
*
* Used to read messages and data from the subprocess.
*/
int InFd;
/** \brief A file descriptor connected to the standard input of the
* subprocess.
*
* Used to send commands and configuration data to the subprocess.
*/
int OutFd;
/** \brief The socket to send SCM_RIGHTS message through
*/
int PrivSepSocketFd;
int PrivSepSocketFdChild;
/** \brief Set to \b true if the worker is in a state in which it
* might generate data or command responses.
*
* \todo Is this right? It's a guess.
*/
bool InReady;
/** \brief Set to \b true if the worker is in a state in which it
* is legal to send commands to it.
*
* \todo Is this right?
*/
bool OutReady;
/** If \b true, debugging output will be sent to std::clog. */
bool Debug;
/** \brief The raw text values of messages received from the
* worker, in sequence.
*/
std::vector<std::string> MessageQueue;
/** \brief Buffers pending writes to the subprocess.
*
* \todo Wouldn't a std::dequeue be more appropriate?
*/
std::string OutQueue;
/** \brief Common code for the constructor.
*
* Initializes NextQueue and NextAcquire to NULL; Process, InFd,
* and OutFd to -1, OutReady and InReady to \b false, and Debug
* from _config.
*/
void Construct();
/** \brief Retrieve any available messages from the subprocess.
*
* The messages are retrieved as in \link strutl.h ReadMessages()\endlink, and
* #MethodFailure() is invoked if an error occurs; in particular,
* if the pipe to the subprocess dies unexpectedly while a message
* is being read.
*
* \return \b true if the messages were successfully read, \b
* false otherwise.
*/
bool ReadMessages();
/** \brief Parse and dispatch pending messages.
*
* This dispatches the message in a manner appropriate for its
* type.
*
* \todo Several message types lack separate handlers.
*
* \sa Capabilities(), SendConfiguration(), MediaChange()
*/
bool RunMessages();
/** \brief Read and dispatch any pending messages from the
* subprocess.
*
* \return \b false if the subprocess died unexpectedly while a
* message was being transmitted.
*/
bool InFdReady();
/** \brief Send any pending commands to the subprocess.
*
* This method will fail if there is no pending output.
*
* \return \b true if all commands were succeeded, \b false if an
* error occurred (in which case MethodFailure() will be invoked).
*/
bool OutFdReady();
/** \brief Handle a 100 Capabilities response from the subprocess.
*
* \param Message the raw text of the message from the subprocess.
*
* The message will be parsed and its contents used to fill
* #Config. If #Config is NULL, this routine is a NOP.
*
* \return \b true.
*/
bool Capabilities(std::string Message);
/** \brief Send a 601 Configuration message (containing the APT
* configuration) to the subprocess.
*
* The APT configuration will be send to the subprocess in a
* message of the following form:
*
* <pre>
* 601 Configuration
* Config-Item: Fully-Qualified-Item=Val
* Config-Item: Fully-Qualified-Item=Val
* ...
* </pre>
*
* \return \b true if the command was successfully sent, \b false
* otherwise.
*/
bool SendConfiguration();
/** \brief Handle a 403 Media Change message.
*
* \param Message the raw text of the message; the Media field
* indicates what type of media should be changed, and the Drive
* field indicates where the media is located.
*
* Invokes pkgAcquireStatus::MediaChange(Media, Drive) to ask the
* user to swap disks; informs the subprocess of the result (via
* 603 Media Changed, with the Failed field set to \b true if the
* user cancelled the media change).
*/
bool MediaChange(std::string Message);
/** \brief Invoked when the worked process dies unexpectedly.
*
* Waits for the subprocess to terminate and generates an error if
* it terminated abnormally, then closes and blanks out all file
* descriptors. Discards all pending messages from the
* subprocess.
*
* \return \b false.
*/
bool MethodFailure();
/** \brief Invoked when a fetch job is completed, either
* successfully or unsuccessfully.
*
* Resets the status information for the worker process.
*/
void ItemDone();
public:
/** \brief The queue entry that is currently being downloaded. */
pkgAcquire::Queue::QItem *CurrentItem;
/** \brief The most recent status string received from the
* subprocess.
*/
std::string Status;
/** \brief How many bytes of the file have been downloaded. Zero
* if the current progress of the file cannot be determined.
*/
unsigned long long CurrentSize;
/** \brief The total number of bytes to be downloaded. Zero if the
* total size of the final is unknown.
*/
unsigned long long TotalSize;
/** \brief How much of the file was already downloaded prior to
* starting this worker.
*/
unsigned long long ResumePoint;
/** \brief Tell the subprocess to download the given item.
*
* \param Item the item to queue up.
* \return \b true if the item was successfully enqueued.
*
* Queues up a 600 URI Acquire message for the given item to be
* sent at the next possible moment. Does \e not flush the output
* queue.
*/
bool QueueItem(pkgAcquire::Queue::QItem *Item);
/** \brief Start up the worker and fill in #Config.
*
* Reads the first message from the worker, which is assumed to be
* a 100 Capabilities message.
*
* \return \b true if all operations completed successfully.
*/
bool Start();
/** \brief Update the worker statistics (CurrentSize, TotalSize,
* etc).
*/
void Pulse();
/** \return The fetch method configuration. */
inline const MethodConfig *GetConf() const {return Config;};
/** \brief Create a new Worker to download files.
*
* \param OwnerQ The queue into which this worker should be
* placed.
*
* \param Config A location in which to store information about
* the fetch method.
*
* \param Log The download progress indicator that should be used
* to report the progress of this worker.
*/
Worker(Queue *OwnerQ,MethodConfig *Config,pkgAcquireStatus *Log);
/** \brief Create a new Worker that should just retrieve
* information about the fetch method.
*
* Nothing in particular forces you to refrain from actually
* downloading stuff, but the various status callbacks won't be
* invoked.
*
* \param Config A location in which to store information about
* the fetch method.
*/
explicit Worker(MethodConfig *Config);
/** \brief Clean up this worker.
*
* Closes the file descriptors; if MethodConfig::NeedsCleanup is
* \b false, also rudely interrupts the worker with a SIGINT.
*/
virtual ~Worker();
private:
APT_HIDDEN void PrepareFiles(char const * const caller, pkgAcquire::Queue::QItem const * const Itm);
};
/** @} */
#endif