summaryrefslogtreecommitdiffstats
path: root/apt-pkg/acquire-worker.h
blob: f59d659d5037565c4d0391c4cb13f534db9046ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
// -*- mode: cpp; mode: fold -*-
// Description								/*{{{*/
/* ######################################################################

   Acquire Worker - Worker process manager

   Each worker class is associated with exactly 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 <string>
#include <vector>
#include <sys/types.h>

/** \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 APT_PUBLIC 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 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);
   APT_HIDDEN bool ReplyAux(pkgAcquire::ItemDesc const &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);
   APT_HIDDEN void HandleFailure(std::vector<pkgAcquire::Item *> const &ItmOwners,
				 pkgAcquire::MethodConfig *const Config, pkgAcquireStatus *const Log,
				 std::string const &Message, bool const errTransient, bool const errAuthErr);
};

/** @} */

#endif