5d45ac03f0c33ab1689a6ca6ffce4eea0cbfb694
[debian/amanda] / xfer-src / xfer-element.h
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 2008, 2009, 2010 Zmanda, Inc.  All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17  *
18  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
19  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
20  */
21
22 /* Base classes for transfer elements.
23  */
24
25 #ifndef XFER_ELEMENT_H
26 #define XFER_ELEMENT_H
27
28 #include <glib.h>
29 #include <glib-object.h>
30 #include "xfer.h"
31 #include "amanda.h"
32 #include "directtcp.h"
33
34 typedef enum {
35     /* sources have no input mechanisms and destinations have no output
36      * mechansisms. */
37     XFER_MECH_NONE,
38
39     /* downstream element will read() from elt->upstream's output_fd; EOF
40      * is indicated by the usual OS mechanism resulting in a zero-length
41      * read, in response to which the downstream element must close
42      * the fd. */
43     XFER_MECH_READFD,
44
45     /* upstream element will write() to elt->downstream's input_fd.  EOF
46      * is indicated by closing the file descriptor. */
47     XFER_MECH_WRITEFD,
48
49     /* downstream element will call elt->upstream->pull_buffer() to
50      * pull a buffer.  EOF is indicated by returning a NULL buffer */
51     XFER_MECH_PULL_BUFFER,
52
53     /* upstream element will call elt->downstream->push_buffer(buf) to push
54      * a buffer.  EOF is indicated by passing a NULL buffer. */
55     XFER_MECH_PUSH_BUFFER,
56
57     /* DirectTCP: downstream sends an array of IP:PORT addresses to which a TCP
58      * connection should be made, then upstream connects to one of the addreses
59      * and sends the data over that connection */
60     XFER_MECH_DIRECTTCP_LISTEN,
61
62     /* DirectTCP: downstream gets IP:PORT addresses from upstream to which a
63      * TCP connection should be made, then connects to one of the addreses and
64      * receives the data over that connection */
65     XFER_MECH_DIRECTTCP_CONNECT,
66
67     /* (sentinel value) */
68     XFER_MECH_MAX,
69 } xfer_mech;
70
71 /*
72  * Description of a pair (input, output) of xfer mechanisms that an
73  * element can support, along with the associated costs.  An array of these
74  * pairs is stored in the class-level variable 'mech_pairs', describing
75  * all of the mechanisms that an element supports.
76  *
77  * Use the XFER_NROPS() and XFER_NTHREADS() macros below in declarations in
78  * order to make declarations more understandable.
79  */
80
81 #define XFER_NROPS(x) (x)
82 #define XFER_NTHREADS(x) (x)
83
84 typedef struct {
85     xfer_mech input_mech;
86     xfer_mech output_mech;
87     guint8 ops_per_byte;        /* number of byte copies or other operations */
88     guint8 nthreads;            /* number of additional threads created */
89 } xfer_element_mech_pair_t;
90
91 /***********************
92  * XferElement
93  *
94  * The virtual base class for all transfer elements
95  */
96
97 GType xfer_element_get_type(void);
98 #define XFER_ELEMENT_TYPE (xfer_element_get_type())
99 #define XFER_ELEMENT(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), xfer_element_get_type(), XferElement)
100 #define XFER_ELEMENT_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), xfer_element_get_type(), XferElement const)
101 #define XFER_ELEMENT_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), xfer_element_get_type(), XferElementClass)
102 #define IS_XFER_ELEMENT(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), xfer_element_get_type ())
103 #define XFER_ELEMENT_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), xfer_element_get_type(), XferElementClass)
104
105 /*
106  * Main object structure
107  */
108
109 typedef struct XferElement {
110     GObject __parent__;
111
112     /* The transfer to which this element is attached */
113     Xfer *xfer; /* set by xfer_new */
114
115     /* assigned input and output mechanisms */
116     xfer_mech input_mech;
117     xfer_mech output_mech;
118
119     /* neighboring xfer elements */
120     struct XferElement *upstream;
121     struct XferElement *downstream;
122
123     /* Information regarding cancellation.  Cancelled and expect_eof are set by
124      * the default cancel() method.  Can_generate_eof should be set during
125      * initialization, and is returned by the default cancel implementation */
126     gboolean cancelled;
127     gboolean expect_eof;
128     gboolean can_generate_eof;
129
130     /* file descriptors for XFER_MECH_READFD and XFER_MECH_WRITEFD.  These
131      * should be set during setup(), and can be accessed by neighboring
132      * elements during start().  These values are shared among multiple
133      * elements, and thus must be accessed with xfer_element_swap_input_fd and
134      * xfer_element_swap_output_fd.  Any file descriptors remaining here at
135      * finalize time will be closed. */
136     gint _input_fd;
137     gint _output_fd;
138
139     /* array of IP:PORT pairs that can be used to connect to this element,
140      * terminated by a 0.0.0.0:0.  The first is set by elements with an input
141      * mech of XFER_MECH_DIRECTTCP_LISTEN and accessed by their upstream
142      * neighbor; the second is set by elements with an output mech of
143      * XFER_MECH_DIRECTTCP_CONNECT and accessed by their downstream neighbor.
144      * */
145
146     DirectTCPAddr *input_listen_addrs;
147     DirectTCPAddr *output_listen_addrs;
148
149     /* cache for repr() */
150     char *repr;
151
152     /* maximum size to transfer */
153     gint64 size;
154 } XferElement;
155
156 /*
157  * Class definition
158  */
159
160 typedef struct {
161     GObjectClass __parent__;
162
163     /* Get a string representation of this element.  The returned string will be freed
164      * when the element is finalized, and is static until that time.  This method is
165      * implemented by XferElement, but can be overridden by classes that can provide
166      * additional useful information about themselves.  Overriding methods can use
167      * the 'repr' instance variable as a cache -- it will be freed on finalize().
168      *
169      * @param elt: the XferElement
170      * @return: statically allocated string
171      */
172     char *(*repr)(XferElement *elt);
173
174     /* Set up this element.  This function is called for all elements in a
175      * transfer before start() is called for any elements.  For mechanisms
176      * where this element supplies a file descriptor, it should set its
177      * input_fd and/or output_fd appropriately; neighboring elements will use
178      * that value in start().  Elements which supply IP:PORT pairs should set
179      * their input_addrs, for neighboring elements to use in start().
180      *
181      * elt->input_mech and elt->output_mech are already set when this function
182      * is called, but upstream and downstream are not.
183      *
184      * If the setup operation fails, the method should send an XMSG_ERROR and
185      * call XMSG_CANCEL, and return False.  In this situation, the start method
186      * will not be called.  The Xfer will appear to the user to start and
187      * immediately fail.
188      *
189      * Note that this method may never be called if other elements' setup methods
190      * fail first.
191      *
192      * @param elt: the XferElement
193      * @return: false on failure, true on success
194      */
195     gboolean (*setup)(XferElement *elt);
196
197     /* set the size of data to transfer, to skip NUL padding bytes
198      * @param elt: the XferElement
199      * @param size: the size of data to transfer
200      * @return: TRUE
201      */
202     gboolean (*set_size)(XferElement *elt, gint64 size);
203
204     /* Start transferring data.  The element downstream of this one will
205      * already be started, while the upstream element will not, so data will
206      * not begin flowing immediately.  It is safe to access attributes of
207      * neighboring elements during this call.
208      *
209      * This method will *not* be called if all elements do not set up
210      * correctly.
211      *
212      * @param elt: the XferElement
213      * @return: TRUE if this element will send XMSG_DONE
214      */
215     gboolean (*start)(XferElement *elt);
216
217     /* Stop transferring data.  The upstream element's cancel method will
218      * already have been called, but due to buffering and synchronization
219      * issues, data may yet arrive.  The element may discard any such data, but
220      * must not fail.  This method is only called for abnormal terminations;
221      * elements should normally stop processing on receiving an EOF indication
222      * from upstream.
223      *
224      * If expect_eof is TRUE, then this element should expect an EOF from its
225      * upstream element, and should drain any remaining data until that EOF
226      * arrives and generate an EOF to the downstream element.  The utility
227      * functions xfer_element_drain_fd and xfer_element_drain_buffers may be
228      * useful for this purpose. This draining is important in order to avoid
229      * hung threads or unexpected SIGPIPEs.
230      *
231      * If expect_eof is FALSE, then the upstream elements are unable to
232      * generate an early EOF, so this element should *not* attempt to drain any
233      * remaining data.  As an example, an FdSource is not active and thus
234      * cannot generate an EOF on request.
235      *
236      * If this element can generate an EOF, it should return TRUE, otherwise
237      * FALSE.
238      *
239      * This method may be called before start or setup if an error is
240      * encountered during setup.
241      *
242      * The default implementation sets self->expect_eof and self->cancelled
243      * appropriately and returns self->can_generate_eof.
244      *
245      * This method is always called from the main thread.  It must not block.
246      *
247      * @param elt: the XferElement
248      * @param expect_eof: element should expect an EOF
249      * @returns: true if this element can return EOF
250      */
251     gboolean (*cancel)(XferElement *elt, gboolean expect_eof);
252
253     /* Get a buffer full of data from this element.  This function is called by
254      * the downstream element under XFER_MECH_PULL_CALL.  It can block indefinitely,
255      * and must only return NULL on EOF.  Responsibility to free the buffer transfers
256      * to the caller.
257      *
258      * @param elt: the XferElement
259      * @param size (output): size of resulting buffer
260      * @returns: buffer pointer
261      */
262     gpointer (*pull_buffer)(XferElement *elt, size_t *size);
263
264     /* A buffer full of data is being sent to this element for processing; this
265      * function is called by the upstream element under XFER_MECH_PUSH_CALL.
266      * It can block indefinitely if the data cannot be processed immediately.
267      * An EOF condition is signaled by call with a NULL buffer.  Responsibility to
268      * free the buffer transfers to the callee.
269      *
270      * @param elt: the XferElement
271      * @param buf: buffer
272      * @param size: size of buffer
273      */
274     void (*push_buffer)(XferElement *elt, gpointer buf, size_t size);
275
276     /* Returns the mech_pairs that this element supports.  The default
277      * implementation just returns the class attribute 'mech_pairs', but
278      * subclasses can dynamically select the available mechanisms by overriding
279      * this method.  Note that the method is called before the setup() method.
280      *
281      * @param elt: the XferElement
282      * @returns: array of mech pairs, terminated by <NONE,NONE>
283      */
284     xfer_element_mech_pair_t *(*get_mech_pairs)(XferElement *elt);
285
286     /* class variables */
287
288     /* This is used by the perl bindings -- it is a class variable giving the
289      * appropriate perl class to wrap this XferElement.  It should be set by
290      * each class's class_init.
291      */
292     const char *perl_class;
293
294     /* Statically allocated array of input/output mechanisms supported by this
295      * class (terminated by <XFER_MECH_NONE,XFER_MECH_NONE>).  The default
296      * get_mech_pairs method returns this. */
297     xfer_element_mech_pair_t *mech_pairs;
298 } XferElementClass;
299
300 /*
301  * Method stubs
302  */
303
304 void xfer_element_unref(XferElement *elt);
305 gboolean xfer_element_link_to(XferElement *elt, XferElement *successor);
306 char *xfer_element_repr(XferElement *elt);
307 gboolean xfer_element_setup(XferElement *elt);
308 gboolean xfer_element_set_size(XferElement *elt, gint64 size);
309 gboolean xfer_element_start(XferElement *elt);
310 void xfer_element_push_buffer(XferElement *elt, gpointer buf, size_t size);
311 gpointer xfer_element_pull_buffer(XferElement *elt, size_t *size);
312 gboolean xfer_element_cancel(XferElement *elt, gboolean expect_eof);
313 xfer_element_mech_pair_t *xfer_element_get_mech_pairs(XferElement *elt);
314
315 /****
316  * Subclass utilities
317  *
318  * These are utilities for subclasses
319  */
320
321 /* Drain UPSTREAM by pulling buffers until EOF
322  *
323  * @param upstream: the element to drain
324  */
325 void xfer_element_drain_buffers(XferElement *upstream);
326
327 /* Drain UPSTREAM by reading until EOF.  This does not close
328  * the file descriptor.
329  *
330  * @param fd: the file descriptor to drain
331  */
332 void xfer_element_drain_fd(int fd);
333
334 /* Atomically swap a value into elt->_input_fd and _output_fd, respectively.
335  * Always use these methods to access the field.
336  *
337  * @param elt: xfer element
338  * @param newfd: new value for the fd field
339  * @returns: old value of the fd field
340  */
341 #define xfer_element_swap_input_fd(elt, newfd) \
342     xfer_atomic_swap_fd((elt)->xfer, &(elt)->_input_fd, newfd)
343 #define xfer_element_swap_output_fd(elt, newfd) \
344     xfer_atomic_swap_fd((elt)->xfer, &(elt)->_output_fd, newfd)
345
346 /***********************
347  * XferElement subclasses
348  *
349  * These simple subclasses do not introduce any additional public members or
350  * methods, so they do not have their own header file.  The functions here
351  * provide their only public interface.  The implementation of these elements
352  * can also provide a good prototype for new elements.
353  */
354
355 /* A transfer source that produces LENGTH bytes of random data, for testing
356  * purposes.
357  *
358  * Implemented in source-random.c
359  *
360  * @param length: bytes to produce, or zero for no limit
361  * @param prng_seed: initial value for random number generator
362  * @return: new element
363  */
364 XferElement *xfer_source_random(guint64 length, guint32 prng_seed);
365
366 /* Get the ending random seed for the xfer_source_random.  Call this after a
367  * transfer has finished, and construct a new xfer_source_random with the seed.
368  * The new source will continue the same random sequence at the next byte.  This
369  * is useful for constructing spanned dumps in testing.
370  *
371  * @param src: XferSourceRandom object
372  * @returns: seed
373  */
374 guint32 xfer_source_random_get_seed(XferElement *src);
375
376 /* A transfer source that produces LENGTH bytes containing repeated
377  * copies of the provided pattern, for testing purposes.
378  *
379  * Implemented in source-pattern.c
380  *
381  * @param length: bytes to produce, or zero for no limit
382  * @param pattern: Pointer to memory containing the desired byte pattern.
383  * @param pattern_length: Size of pattern to repeat.
384  * @return: new element
385  */
386 XferElement *xfer_source_pattern(guint64 length, void * pattern,
387                                  size_t pattern_length);
388
389 /* A transfer source that provides bytes read from a file descriptor.
390  * Reading continues until EOF, but the file descriptor is not closed.
391  *
392  * Implemented in source-fd.c
393  *
394  * @param fd: the file descriptor from which to read
395  * @return: new element
396  */
397 XferElement * xfer_source_fd(
398     int fd);
399
400 /* A transfer source that exposes its listening DirectTCPAddrs (via
401  * elt->input_listen_addrs) for external use
402  *
403  * Implemented in source-directtcp-listen.c
404  *
405  * @return: new element
406  */
407 XferElement * xfer_source_directtcp_listen(void);
408
409 /* A transfer source that connects to a DirectTCP address and pulls data
410  * from it into the transfer.
411  *
412  * Implemented in source-directtcp-listen.c
413  *
414  * @param addrs: DirectTCP addresses to connect to
415  * @return: new element
416  */
417 XferElement * xfer_source_directtcp_connect(DirectTCPAddr *addrs);
418
419 /* A transfer filter that executes an external application, feeding it data on
420  * stdin and taking the results on stdout.
421  *
422  * The memory for ARGV becomes the property of the transfer element and will be
423  * g_strfreev'd when the xfer is destroyed.
424  *
425  * Implemented in filter-process.c
426  *
427  * @param argv: NULL-terminated command-line arguments
428  * @param need_root: become root before exec'ing the subprocess
429  * @return: new element
430  */
431 XferElement *xfer_filter_process(gchar **argv,
432     gboolean need_root);
433
434 /* A transfer filter that just applies a bytewise XOR transformation to the data
435  * that passes through it.
436  *
437  * Implemented in filter-xor.c
438  *
439  * @param xor_key: key for xor operations
440  * @return: new element
441  */
442 XferElement *xfer_filter_xor(
443     unsigned char xor_key);
444
445 /* A transfer destination that consumes all bytes it is given, optionally
446  * validating that they match those produced by source_random
447  *
448  * Implemented in dest-null.c
449  *
450  * @param prng_seed: if nonzero, validate that the datastream matches
451  *      that produced by a random source with this random seed.  If zero,
452  *      no validation is performed.
453  * @return: new element
454  */
455 XferElement *xfer_dest_null(
456     guint32 prng_seed);
457
458 /* A transfer destination that writes bytes to a file descriptor.  The file
459  * descriptor is not closed when the transfer is complete.
460  *
461  * Implemented in dest-fd.c
462  *
463  * @param fd: file descriptor to which to write
464  * @return: new element
465  */
466 XferElement *xfer_dest_fd(
467     int fd);
468
469 /* A transfer destination that writes bytes to an in-memory buffer.
470  *
471  * Implemented in dest-buffer.c
472  *
473  * @param max_size: maximum size for the buffer, or zero for no limit
474  * @return: new element
475  */
476 XferElement *xfer_dest_buffer(
477     gsize max_size);
478
479 /* Get the buffer and size from an XferDestBuffer.  The resulting buffer
480  * will remain allocated until the XDB itself is freed.
481  *
482  * Implemented in dest-buffer.c
483  *
484  * @param elt: the element
485  * @param buf (output): buffer pointer
486  * @param size (output): buffer size
487  */
488 void xfer_dest_buffer_get(
489     XferElement *elt,
490     gpointer *buf,
491     gsize *size);
492
493 /* A transfer dest that connects to a DirectTCPAddr and sends data to
494  * it
495  *
496  * Implemented in dest-directtcp-connect.c
497  *
498  * @param addrs: DirectTCP addresses to connect to
499  * @return: new element
500  */
501 XferElement * xfer_dest_directtcp_connect(DirectTCPAddr *addrs);
502
503 /* A transfer dest that listens for a DirecTCP connection and sends data to it
504  * when connected.  Listening addresses are exposed at
505  * elt->output_listen_addrs.
506  *
507  * Implemented in dest-directtcp-listen.c
508  *
509  * @return: new element
510  */
511 XferElement * xfer_dest_directtcp_listen(void);
512
513 #endif