diff --git a/.x-sc_avoid_write b/.x-sc_avoid_write
index e0f94d6027..9e37248b24 100644
--- a/.x-sc_avoid_write
+++ b/.x-sc_avoid_write
@@ -1,3 +1,4 @@
+^src/libvirt\.c$
^src/util/util\.c$
^src/xen/xend_internal\.c$
^daemon/libvirtd.c$
diff --git a/docs/libvirt-api.xml b/docs/libvirt-api.xml
index f5018b9d6c..5981c0ed68 100644
--- a/docs/libvirt-api.xml
+++ b/docs/libvirt-api.xml
@@ -25,6 +25,7 @@
+
@@ -41,13 +42,15 @@
+
+
-
+
@@ -77,6 +80,7 @@
+
@@ -90,6 +94,7 @@
+
@@ -106,9 +111,11 @@
+
+
@@ -126,11 +133,13 @@
+
+
@@ -189,6 +198,7 @@
+
@@ -201,6 +211,7 @@
+
@@ -208,6 +219,7 @@
+
@@ -226,6 +238,7 @@
+
@@ -235,6 +248,7 @@
+
@@ -244,16 +258,20 @@
+
+
+
+
@@ -305,9 +323,11 @@
+
+
@@ -337,8 +357,10 @@
+
+
@@ -350,6 +372,8 @@
+
+
@@ -710,6 +734,11 @@
+
+
+
+
+
@@ -881,6 +910,12 @@ see note above'/>
+
+
+
+
+
+
@@ -2657,5 +2692,289 @@ the reference count.]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/libvirt-refs.xml b/docs/libvirt-refs.xml
index d7255de3fe..e7fbedf8c5 100644
--- a/docs/libvirt-refs.xml
+++ b/docs/libvirt-refs.xml
@@ -173,6 +173,11 @@
+
+
+
+
+
@@ -474,6 +479,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -654,6 +678,11 @@
+
+
+
+
+
@@ -959,6 +988,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1040,6 +1088,9 @@
+
+
+
@@ -1078,6 +1129,10 @@
+
+
+
+
@@ -1125,6 +1180,7 @@
+
@@ -1225,6 +1281,7 @@
+
@@ -1317,6 +1374,7 @@
+
@@ -1425,6 +1483,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1442,6 +1525,12 @@
+
+
+
+
+
+
@@ -1526,6 +1615,11 @@
+
+
+
+
+
@@ -1803,6 +1897,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1939,6 +2052,11 @@
+
+
+
+
+
@@ -2028,6 +2146,7 @@
+
@@ -2059,6 +2178,9 @@
+
+
+
@@ -2074,6 +2196,9 @@
+
+
+
@@ -2144,6 +2269,10 @@
+
+
+
+
@@ -2214,6 +2343,9 @@
+
+
+
@@ -2248,6 +2380,8 @@
+
+
@@ -2263,8 +2397,6 @@
-
-
@@ -2278,6 +2410,10 @@
+
+
+
+
@@ -2422,8 +2558,17 @@
+
+
+
+
+
+
+
+
+
@@ -2519,6 +2664,9 @@
+
+
+
@@ -2543,6 +2691,7 @@
+
@@ -2564,6 +2713,10 @@
+
+
+
+
@@ -2578,6 +2731,9 @@
+
+
+
@@ -2622,6 +2778,7 @@
+
@@ -2641,6 +2798,8 @@
+
+
@@ -2708,8 +2867,6 @@
-
-
@@ -2749,6 +2906,9 @@
+
+
+
@@ -2784,6 +2944,11 @@
+
+
+
+
+
@@ -2800,6 +2965,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -2864,6 +3040,11 @@
+
+
+
+
+
@@ -2884,6 +3065,7 @@
+
@@ -2940,6 +3122,9 @@
+
+
+
@@ -2973,6 +3158,8 @@
+
+
@@ -2982,6 +3169,10 @@
+
+
+
+
@@ -2995,6 +3186,8 @@
+
+
@@ -3003,6 +3196,11 @@
+
+
+
+
+
@@ -3015,6 +3213,14 @@
+
+
+
+
+
+
+
+
@@ -3031,8 +3237,14 @@
+
+
+
+
+
+
@@ -3080,6 +3292,9 @@
+
+
+
@@ -3190,8 +3405,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3203,6 +3430,8 @@
+
+
@@ -3243,6 +3472,7 @@
+
@@ -3251,6 +3481,12 @@
+
+
+
+
+
+
@@ -3268,9 +3504,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3279,6 +3529,11 @@
+
+
+
+
+
@@ -3296,6 +3551,8 @@
+
+
@@ -3316,33 +3573,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -3354,6 +3588,8 @@
+
+
@@ -3383,6 +3619,12 @@
+
+
+
+
+
+
@@ -3449,6 +3691,10 @@
+
+
+
+
@@ -3456,6 +3702,10 @@
+
+
+
+
@@ -3465,6 +3715,12 @@
+
+
+
+
+
+
@@ -3474,6 +3730,7 @@
+
@@ -3507,6 +3764,9 @@
+
+
+
@@ -3529,6 +3789,10 @@
+
+
+
+
@@ -3537,6 +3801,12 @@
+
+
+
+
+
+
@@ -3554,10 +3824,20 @@
+
+
+
+
+
+
+
+
+
+
@@ -3577,6 +3857,10 @@
+
+
+
+
@@ -3584,10 +3868,15 @@
+
+
+
+
+
@@ -3611,6 +3900,7 @@
+
@@ -3633,6 +3923,8 @@
+
+
@@ -3705,25 +3997,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -3767,6 +4040,8 @@
+
+
@@ -3779,10 +4054,20 @@
+
+
+
+
+
+
+
+
+
+
@@ -3847,6 +4132,9 @@
+
+
+
@@ -3906,6 +4194,9 @@
+
+
+
@@ -3964,11 +4255,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -3980,6 +4283,9 @@
+
+
+
@@ -4028,6 +4334,11 @@
+
+
+
+
+
@@ -4061,9 +4372,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4081,6 +4406,7 @@
+
@@ -4100,6 +4426,7 @@
+
@@ -4108,6 +4435,7 @@
+
@@ -4120,6 +4448,10 @@
+
+
+
+
@@ -4201,6 +4533,7 @@
+
@@ -4215,6 +4548,7 @@
+
@@ -4234,6 +4568,11 @@
+
+
+
+
+
@@ -4241,6 +4580,7 @@
+
@@ -4248,6 +4588,8 @@
+
+
@@ -4265,6 +4607,7 @@
+
@@ -4274,11 +4617,16 @@
+
+
+
+
+
@@ -4315,34 +4663,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
@@ -4355,6 +4682,7 @@
+
@@ -4388,6 +4716,7 @@
+
@@ -4431,9 +4760,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -4456,6 +4803,7 @@
+
@@ -4486,6 +4834,13 @@
+
+
+
+
+
+
+
@@ -4505,9 +4860,16 @@
+
+
+
+
+
+
+
@@ -4567,6 +4929,12 @@
+
+
+
+
+
+
@@ -4664,6 +5032,8 @@
+
+
@@ -4677,6 +5047,9 @@
+
+
+
@@ -4699,6 +5072,7 @@
+
@@ -4713,6 +5087,8 @@
+
+
@@ -4734,9 +5110,15 @@
+
+
+
+
+
+
@@ -4768,12 +5150,20 @@
+
+
+
+
+
+
+
+
@@ -4786,6 +5176,12 @@
+
+
+
+
+
+
@@ -4902,6 +5298,8 @@
+
+
@@ -4940,6 +5338,8 @@
+
+
@@ -4953,6 +5353,12 @@
+
+
+
+
+
+
@@ -5037,6 +5443,8 @@
+
+
@@ -5044,6 +5452,12 @@
+
+
+
+
+
+
@@ -5109,6 +5523,10 @@
+
+
+
+
@@ -5163,25 +5581,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -5269,6 +5668,8 @@
+
+
@@ -5293,6 +5694,14 @@
+
+
+
+
+
+
+
+
@@ -5323,6 +5732,12 @@
+
+
+
+
+
+
@@ -5339,9 +5754,12 @@
+
+
+
@@ -5352,6 +5770,8 @@
+
+
@@ -5382,6 +5802,11 @@
+
+
+
+
+
@@ -5406,6 +5831,9 @@
+
+
+
@@ -5416,6 +5844,8 @@
+
+
@@ -5438,6 +5868,9 @@
+
+
+
@@ -5445,6 +5878,7 @@
+
@@ -5457,6 +5891,8 @@
+
+
@@ -5469,6 +5905,9 @@
+
+
+
@@ -5495,6 +5934,8 @@
+
+
@@ -5504,6 +5945,8 @@
+
+
@@ -5515,6 +5958,10 @@
+
+
+
+
@@ -5530,6 +5977,8 @@
+
+
@@ -5544,6 +5993,8 @@
+
+
@@ -5552,6 +6003,7 @@
+
@@ -5571,6 +6023,7 @@
+
@@ -5584,12 +6037,18 @@
+
+
+
+
+
+
@@ -5655,11 +6114,13 @@
+
+
@@ -5681,6 +6142,8 @@
+
+
@@ -5691,6 +6154,7 @@
+
@@ -5720,6 +6184,9 @@
+
+
+
@@ -5752,6 +6219,10 @@
+
+
+
+
@@ -5780,6 +6251,9 @@
+
+
+
@@ -5804,6 +6278,9 @@
+
+
+
@@ -5811,12 +6288,17 @@
+
+
+
+
+
@@ -5826,6 +6308,8 @@
+
+
@@ -5839,11 +6323,13 @@
+
+
@@ -5890,6 +6376,13 @@
+
+
+
+
+
+
+
@@ -5897,6 +6390,12 @@
+
+
+
+
+
+
@@ -5915,10 +6414,16 @@
+
+
+
+
+
+
@@ -5942,6 +6447,8 @@
+
+
@@ -5964,12 +6471,17 @@
+
+
+
+
+
@@ -6020,9 +6532,17 @@
+
+
+
+
+
+
+
+
@@ -6037,6 +6557,10 @@
+
+
+
+
@@ -6062,6 +6586,7 @@
+
@@ -6139,6 +6664,10 @@
+
+
+
+
@@ -6165,6 +6694,9 @@
+
+
+
@@ -6176,6 +6708,7 @@
+
@@ -6284,12 +6817,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -6329,33 +6880,12 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -6375,12 +6905,23 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -6402,6 +6943,9 @@
+
+
+
@@ -6500,6 +7044,7 @@
+
@@ -6537,6 +7082,13 @@
+
+
+
+
+
+
+
@@ -6551,12 +7103,23 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -6564,6 +7127,7 @@
+
@@ -6609,12 +7173,22 @@
+
+
+
+
+
+
+
+
+
+
@@ -6652,6 +7226,10 @@
+
+
+
+
@@ -6664,6 +7242,8 @@
+
+
@@ -6673,36 +7253,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -6723,6 +7273,9 @@
+
+
+
@@ -6775,6 +7328,10 @@
+
+
+
+
@@ -6788,6 +7345,8 @@
+
+
@@ -6796,10 +7355,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
@@ -6925,6 +7496,10 @@
+
+
+
+
@@ -6946,16 +7521,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7035,6 +7625,7 @@
+
@@ -7049,21 +7640,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -7123,6 +7699,9 @@
+
+
+
@@ -7145,6 +7724,11 @@
+
+
+
+
+
@@ -7227,6 +7811,7 @@
+
@@ -7334,6 +7919,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7365,6 +8008,10 @@
+
+
+
+
@@ -7382,6 +8029,9 @@
+
+
+
@@ -7399,6 +8049,8 @@
+
+
@@ -7426,6 +8078,8 @@
+
+
@@ -7455,6 +8109,8 @@
+
+
@@ -7502,6 +8158,9 @@
+
+
+
@@ -7510,10 +8169,13 @@
+
+
+
@@ -7559,13 +8221,14 @@
+
-
-
-
+
+
+
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 6028d5fa9e..4e63e48980 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -110,6 +110,24 @@ typedef enum {
VIR_DOMAIN_NONE = 0
} virDomainCreateFlags;
+
+
+/**
+ * virStream:
+ *
+ * a virStream is a private structure representing a data stream.
+ */
+typedef struct _virStream virStream;
+
+/**
+ * virStreamPtr:
+ *
+ * a virStreamPtr is pointer to a virStream private structure, this is the
+ * type used to reference a data stream in the API.
+ */
+typedef virStream *virStreamPtr;
+
+
/**
* VIR_SECURITY_LABEL_BUFLEN:
*
@@ -1502,6 +1520,127 @@ int virSecretUndefine (virSecretPtr secret);
int virSecretRef (virSecretPtr secret);
int virSecretFree (virSecretPtr secret);
+typedef enum {
+ VIR_STREAM_NONBLOCK = (1 << 0),
+} virStreamFlags;
+
+virStreamPtr virStreamNew(virConnectPtr conn,
+ unsigned int flags);
+int virStreamRef(virStreamPtr st);
+
+int virStreamSend(virStreamPtr st,
+ const char *data,
+ size_t nbytes);
+
+int virStreamRecv(virStreamPtr st,
+ char *data,
+ size_t nbytes);
+
+
+/**
+ * virStreamSourceFunc:
+ *
+ * @st: the stream object
+ * @data: preallocated array to be filled with data
+ * @nbytes: size of the data array
+ * @opaque: optional application provided data
+ *
+ * The virStreamSourceFunc callback is used together
+ * with the virStreamSendAll function for libvirt to
+ * obtain the data that is to be sent.
+ *
+ * The callback will be invoked multiple times,
+ * fetching data in small chunks. The application
+ * should fill the 'data' array with upto 'nbytes'
+ * of data and then return the number actual number
+ * of bytes. The callback will continue to be
+ * invoked until it indicates the end of the source
+ * has been reached by returning 0. A return value
+ * of -1 at any time will abort the send operation
+ *
+ * Returns the number of bytes filled, 0 upon end
+ * of file, or -1 upon error
+ */
+typedef int (*virStreamSourceFunc)(virStreamPtr st,
+ char *data,
+ size_t nbytes,
+ void *opaque);
+
+int virStreamSendAll(virStreamPtr st,
+ virStreamSourceFunc handler,
+ void *opaque);
+
+/**
+ * virStreamSinkFunc:
+ *
+ * @st: the stream object
+ * @data: preallocated array to be filled with data
+ * @nbytes: size of the data array
+ * @opaque: optional application provided data
+ *
+ * The virStreamSinkFunc callback is used together
+ * with the virStreamRecvAll function for libvirt to
+ * provide the data that has been received.
+ *
+ * The callback will be invoked multiple times,
+ * providing data in small chunks. The application
+ * should consume up 'nbytes' from the 'data' array
+ * of data and then return the number actual number
+ * of bytes consumed. The callback will continue to be
+ * invoked until it indicates the end of the stream
+ * has been reached. A return value of -1 at any time
+ * will abort the receive operation
+ *
+ * Returns the number of bytes consumed or -1 upon
+ * error
+ */
+typedef int (*virStreamSinkFunc)(virStreamPtr st,
+ const char *data,
+ size_t nbytes,
+ void *opaque);
+
+int virStreamRecvAll(virStreamPtr st,
+ virStreamSinkFunc handler,
+ void *opaque);
+
+typedef enum {
+ VIR_STREAM_EVENT_READABLE = (1 << 0),
+ VIR_STREAM_EVENT_WRITABLE = (1 << 1),
+ VIR_STREAM_EVENT_ERROR = (1 << 2),
+ VIR_STREAM_EVENT_HANGUP = (1 << 3),
+} virStreamEventType;
+
+
+/**
+ * virStreamEventCallback:
+ *
+ * @stream: stream on which the event occurred
+ * @events: bitset of events from virEventHandleType constants
+ * @opaque: user data registered with handle
+ *
+ * Callback for receiving stream events. The callback will
+ * be invoked once for each event which is pending.
+ */
+typedef void (*virStreamEventCallback)(virStreamPtr stream, int events, void *opaque);
+
+int virStreamEventAddCallback(virStreamPtr stream,
+ int events,
+ virStreamEventCallback cb,
+ void *opaque,
+ virFreeCallback ff);
+
+int virStreamEventUpdateCallback(virStreamPtr stream,
+ int events);
+
+int virStreamEventRemoveCallback(virStreamPtr stream);
+
+
+int virStreamFinish(virStreamPtr st);
+int virStreamAbort(virStreamPtr st);
+
+int virStreamFree(virStreamPtr st);
+
+
#ifdef __cplusplus
}
#endif
diff --git a/python/Makefile.am b/python/Makefile.am
index 95ae84d2e4..cda655981e 100644
--- a/python/Makefile.am
+++ b/python/Makefile.am
@@ -13,7 +13,9 @@ DOCS_DIR = $(datadir)/doc/libvirt-python-$(LIBVIRT_VERSION)
DOCS = ${srcdir}/TODO
-CLASSES_EXTRA = libvirt-override-virConnect.py
+CLASSES_EXTRA = \
+ libvirt-override-virConnect.py \
+ libvirt-override-virStream.py
EXTRA_DIST = \
generator.py \
diff --git a/python/generator.py b/python/generator.py
index 178a415183..48ad14b855 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -282,6 +282,11 @@ py_types = {
'const virSecretPtr': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
'const virSecret *': ('O', "virSecret", "virSecretPtr", "virSecretPtr"),
+
+ 'virStreamPtr': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
+ 'const virStreamPtr': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
+ 'virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
+ 'const virStream *': ('O', "virStream", "virStreamPtr", "virStreamPtr"),
}
py_return_types = {
@@ -338,6 +343,8 @@ skip_impl = (
'virSecretGetUUID',
'virSecretGetUUIDString',
'virSecretLookupByUUID',
+ 'virStreamRecv',
+ 'virStreamSend',
'virStoragePoolGetUUID',
'virStoragePoolGetUUIDString',
'virStoragePoolLookupByUUID',
@@ -373,6 +380,11 @@ skip_function = (
'virConnectDomainEventDeregister', # overridden in virConnect.py
'virSaveLastError', # We have our own python error wrapper
'virFreeError', # Only needed if we use virSaveLastError
+ 'virStreamEventAddCallback',
+ 'virStreamRecvAll',
+ 'virStreamSendAll',
+ 'virStreamRef',
+ 'virStreamFree',
)
@@ -643,6 +655,8 @@ classes_type = {
"virNodeDevice *": ("._o", "virNodeDevice(self, _obj=%s)", "virNodeDevice"),
"virSecretPtr": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
"virSecret *": ("._o", "virSecret(self, _obj=%s)", "virSecret"),
+ "virStreamPtr": ("._o", "virStream(self, _obj=%s)", "virStream"),
+ "virStream *": ("._o", "virStream(self, _obj=%s)", "virStream"),
"virConnectPtr": ("._o", "virConnect(_obj=%s)", "virConnect"),
"virConnect *": ("._o", "virConnect(_obj=%s)", "virConnect"),
}
@@ -652,7 +666,8 @@ converter_type = {
primary_classes = ["virDomain", "virNetwork", "virInterface",
"virStoragePool", "virStorageVol",
- "virConnect", "virNodeDevice", "virSecret" ]
+ "virConnect", "virNodeDevice", "virSecret",
+ "virStream"]
classes_ancestor = {
}
@@ -663,7 +678,9 @@ classes_destructors = {
"virStoragePool": "virStoragePoolFree",
"virStorageVol": "virStorageVolFree",
"virNodeDevice" : "virNodeDeviceFree",
- "virSecret": "virSecretFree"
+ "virSecret": "virSecretFree",
+ # We hand-craft __del__ for this one
+ #"virStream": "virStreamFree",
}
functions_noexcept = {
@@ -782,6 +799,11 @@ def nameFixup(name, classe, type, file):
elif name[0:9] == 'virSecret':
func = name[9:]
func = string.lower(func[0:1]) + func[1:]
+ elif name[0:12] == 'virStreamNew':
+ func = "newStream"
+ elif name[0:9] == 'virStream':
+ func = name[9:]
+ func = string.lower(func[0:1]) + func[1:]
elif name[0:17] == "virStoragePoolGet":
func = name[17:]
func = string.lower(func[0:1]) + func[1:]
@@ -1059,7 +1081,8 @@ def buildWrappers():
classes_ancestor[classname]))
else:
classes.write("class %s:\n" % (classname))
- if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool", "virStorageVol", "virNodeDevice", "virSecret" ]:
+ if classname in [ "virDomain", "virNetwork", "virInterface", "virStoragePool",
+ "virStorageVol", "virNodeDevice", "virSecret","virStream" ]:
classes.write(" def __init__(self, conn, _obj=None):\n")
else:
classes.write(" def __init__(self, _obj=None):\n")
@@ -1067,7 +1090,8 @@ def buildWrappers():
list = reference_keepers[classname]
for ref in list:
classes.write(" self.%s = None\n" % ref[1])
- if classname in [ "virDomain", "virNetwork", "virInterface", "virNodeDevice", "virSecret" ]:
+ if classname in [ "virDomain", "virNetwork", "virInterface",
+ "virNodeDevice", "virSecret", "virStream" ]:
classes.write(" self._conn = conn\n")
elif classname in [ "virStorageVol", "virStoragePool" ]:
classes.write(" self._conn = conn\n" + \
diff --git a/python/libvirt-override-virStream.py b/python/libvirt-override-virStream.py
new file mode 100644
index 0000000000..f50a7efe90
--- /dev/null
+++ b/python/libvirt-override-virStream.py
@@ -0,0 +1,20 @@
+ def __del__(self):
+ try:
+ if self.cb:
+ libvirtmod.virStreamEventRemoveCallback(self._o)
+ except AttributeError:
+ pass
+
+ if self._o != None:
+ libvirtmod.virStreamFree(self._o)
+ self._o = None
+
+ def eventAddCallback(self, cb, opaque):
+ """ """
+ try:
+ self.cb = cb
+ self.opaque = opaque
+ ret = libvirtmod.virStreamEventAddCallback(self._o, self)
+ if ret == -1: raise libvirtError ('virStreamEventAddCallback() failed', conn=self._conn)
+ except AttributeError:
+ pass
diff --git a/python/typewrappers.c b/python/typewrappers.c
index 0d8ac97583..9ba99de0db 100644
--- a/python/typewrappers.c
+++ b/python/typewrappers.c
@@ -206,6 +206,19 @@ libvirt_virSecretPtrWrap(virSecretPtr node)
return (ret);
}
+PyObject *
+libvirt_virStreamPtrWrap(virStreamPtr node)
+{
+ PyObject *ret;
+
+ if (node == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ ret = PyCObject_FromVoidPtrAndDesc(node, (char *) "virStreamPtr", NULL);
+ return (ret);
+}
+
PyObject *
libvirt_virEventHandleCallbackWrap(virEventHandleCallback node)
{
diff --git a/python/typewrappers.h b/python/typewrappers.h
index 99d5805f2b..61f72490be 100644
--- a/python/typewrappers.h
+++ b/python/typewrappers.h
@@ -92,6 +92,15 @@ typedef struct {
} PyvirSecret_Object;
+#define PyvirStream_Get(v) (((v) == Py_None) ? NULL : \
+ (((PyvirStream_Object *)(v))->obj))
+
+typedef struct {
+ PyObject_HEAD
+ virStreamPtr obj;
+} PyvirStream_Object;
+
+
#define PyvirEventHandleCallback_Get(v) (((v) == Py_None) ? NULL : \
(((PyvirEventHandleCallback_Object *)(v))->obj))
@@ -144,6 +153,7 @@ PyObject * libvirt_virFreeCallbackWrap(virFreeCallback node);
PyObject * libvirt_virVoidPtrWrap(void* node);
PyObject * libvirt_virNodeDevicePtrWrap(virNodeDevicePtr node);
PyObject * libvirt_virSecretPtrWrap(virSecretPtr node);
+PyObject * libvirt_virStreamPtrWrap(virStreamPtr node);
/* Provide simple macro statement wrappers (adapted from GLib, in turn from Perl):
diff --git a/src/datatypes.c b/src/datatypes.c
index 530076c0ba..6741b9e4dd 100644
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -1162,6 +1162,7 @@ virUnrefNodeDevice(virNodeDevicePtr dev) {
return (refs);
}
+
/**
* virGetSecret:
* @conn: the hypervisor connection
@@ -1297,3 +1298,61 @@ virUnrefSecret(virSecretPtr secret) {
virMutexUnlock(&secret->conn->lock);
return refs;
}
+
+virStreamPtr virGetStream(virConnectPtr conn) {
+ virStreamPtr ret = NULL;
+
+ virMutexLock(&conn->lock);
+
+ if (VIR_ALLOC(ret) < 0) {
+ virReportOOMError(conn);
+ goto error;
+ }
+ ret->magic = VIR_STREAM_MAGIC;
+ ret->conn = conn;
+ conn->refs++;
+ ret->refs++;
+ virMutexUnlock(&conn->lock);
+ return(ret);
+
+error:
+ virMutexUnlock(&conn->lock);
+ VIR_FREE(ret);
+ return(NULL);
+}
+
+static void
+virReleaseStream(virStreamPtr st) {
+ virConnectPtr conn = st->conn;
+ DEBUG("release dev %p", st);
+
+ st->magic = -1;
+ VIR_FREE(st);
+
+ DEBUG("unref connection %p %d", conn, conn->refs);
+ conn->refs--;
+ if (conn->refs == 0) {
+ virReleaseConnect(conn);
+ /* Already unlocked mutex */
+ return;
+ }
+
+ virMutexUnlock(&conn->lock);
+}
+
+int virUnrefStream(virStreamPtr st) {
+ int refs;
+
+ virMutexLock(&st->conn->lock);
+ DEBUG("unref stream %p %d", st, st->refs);
+ st->refs--;
+ refs = st->refs;
+ if (refs == 0) {
+ virReleaseStream(st);
+ /* Already unlocked mutex */
+ return (0);
+ }
+
+ virMutexUnlock(&st->conn->lock);
+ return (refs);
+}
diff --git a/src/datatypes.h b/src/datatypes.h
index a33c365a6a..afb51dcbd6 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -109,6 +109,17 @@
#define VIR_IS_CONNECTED_SECRET(obj) (VIR_IS_SECRET(obj) && VIR_IS_CONNECT((obj)->conn))
+/**
+ * VIR_STREAM_MAGIC:
+ *
+ * magic value used to protect the API when pointers to stream structures
+ * are passed down by the users.
+ */
+#define VIR_STREAM_MAGIC 0x1DEAD666
+#define VIR_IS_STREAM(obj) ((obj) && (obj)->magic==VIR_STREAM_MAGIC)
+#define VIR_IS_CONNECTED_STREAM(obj) (VIR_IS_STREAM(obj) && VIR_IS_CONNECT((obj)->conn))
+
+
/**
* _virConnect:
*
@@ -261,6 +272,25 @@ struct _virSecret {
};
+typedef int (*virStreamAbortFunc)(virStreamPtr, void *opaque);
+typedef int (*virStreamFinishFunc)(virStreamPtr, void *opaque);
+
+/**
+ * _virStream:
+ *
+ * Internal structure associated with an input stream
+ */
+struct _virStream {
+ unsigned int magic;
+ virConnectPtr conn;
+ int refs;
+ int flags;
+
+ virStreamDriverPtr driver;
+ void *privateData;
+};
+
+
/************************************************************************
* *
* API for domain/connections (de)allocations and lookups *
@@ -303,4 +333,7 @@ virSecretPtr virGetSecret(virConnectPtr conn,
const char *usageID);
int virUnrefSecret(virSecretPtr secret);
+virStreamPtr virGetStream(virConnectPtr conn);
+int virUnrefStream(virStreamPtr st);
+
#endif
diff --git a/src/driver.h b/src/driver.h
index d4f972f3e9..6a3dcc2891 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -879,6 +879,41 @@ struct _virSecretDriver {
virDrvSecretUndefine undefine;
};
+
+typedef struct _virStreamDriver virStreamDriver;
+typedef virStreamDriver *virStreamDriverPtr;
+
+typedef int (*virDrvStreamSend)(virStreamPtr st,
+ const char *data,
+ size_t nbytes);
+typedef int (*virDrvStreamRecv)(virStreamPtr st,
+ char *data,
+ size_t nbytes);
+
+typedef int (*virDrvStreamEventAddCallback)(virStreamPtr stream,
+ int events,
+ virStreamEventCallback cb,
+ void *opaque,
+ virFreeCallback ff);
+
+typedef int (*virDrvStreamEventUpdateCallback)(virStreamPtr stream,
+ int events);
+typedef int (*virDrvStreamEventRemoveCallback)(virStreamPtr stream);
+typedef int (*virDrvStreamFinish)(virStreamPtr st);
+typedef int (*virDrvStreamAbort)(virStreamPtr st);
+
+
+struct _virStreamDriver {
+ virDrvStreamSend streamSend;
+ virDrvStreamRecv streamRecv;
+ virDrvStreamEventAddCallback streamAddCallback;
+ virDrvStreamEventUpdateCallback streamUpdateCallback;
+ virDrvStreamEventRemoveCallback streamRemoveCallback;
+ virDrvStreamFinish streamFinish;
+ virDrvStreamAbort streamAbort;
+};
+
+
/*
* Registration
* TODO: also need ways to (des)activate a given driver
diff --git a/src/libvirt.c b/src/libvirt.c
index f164f60650..48e7b5bcb2 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -561,6 +561,10 @@ virLibNodeDeviceError(virNodeDevicePtr dev, virErrorNumber error,
errmsg, info, NULL, 0, 0, errmsg, info);
}
+#define virLibStreamError(conn, code, fmt...) \
+ virReportErrorHelper(conn, VIR_FROM_NONE, code, __FILE__, \
+ __FUNCTION__, __LINE__, fmt)
+
/**
* virLibSecretError:
* @secret: the secret if available
@@ -9394,3 +9398,700 @@ virSecretFree(virSecretPtr secret)
return -1;
return 0;
}
+
+
+/**
+ * virStreamNew:
+ * @conn: pointer to the connection
+ * @flags: control features of the stream
+ *
+ * Creates a new stream object which can be used to perform
+ * streamed I/O with other public API function.
+ *
+ * When no longer needed, a stream object must be released
+ * with virStreamFree. If a data stream has been used,
+ * then the application must call virStreamFinish or
+ * virStreamAbort before free'ing to, in order to notify
+ * the driver of termination.
+ *
+ * If a non-blocking data stream is required passed
+ * VIR_STREAM_NONBLOCK for flags, otherwise pass 0.
+ *
+ * Returns the new stream, or NULL upon error
+ */
+virStreamPtr
+virStreamNew(virConnectPtr conn,
+ unsigned int flags)
+{
+ virStreamPtr st;
+
+ DEBUG("conn=%p, flags=%u", conn, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECT(conn)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (NULL);
+ }
+
+ st = virGetStream(conn);
+ if (st)
+ st->flags = flags;
+
+ return st;
+}
+
+
+/**
+ * virStreamRef:
+ * @stream: pointer to the stream
+ *
+ * Increment the reference count on the stream. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virStreamFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+virStreamRef(virStreamPtr stream)
+{
+ if ((!VIR_IS_CONNECTED_STREAM(stream))) {
+ virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
+ return(-1);
+ }
+ virMutexLock(&stream->conn->lock);
+ DEBUG("stream=%p refs=%d", stream, stream->refs);
+ stream->refs++;
+ virMutexUnlock(&stream->conn->lock);
+ return 0;
+}
+
+
+/**
+ * virStreamSend:
+ * @stream: pointer to the stream object
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Write a series of bytes to the stream. This method may
+ * block the calling application for an arbitrary amount
+ * of time. Once an application has finished sending data
+ * it should call virStreamFinish to wait for succesful
+ * confirmation from the driver, or detect any error
+ *
+ * This method may not be used if a stream source has been
+ * registered
+ *
+ * Errors are not guaranteed to be reported synchronously
+ * with the call, but may instead be delayed until a
+ * subsequent call.
+ *
+ * A example using this with a hypothetical file upload
+ * API looks like
+ *
+ * virStreamPtr st = virStreamNew(conn, 0);
+ * int fd = open("demo.iso", O_RDONLY)
+ *
+ * virConnectUploadFile(conn, "demo.iso", st);
+ *
+ * while (1) {
+ * char buf[1024];
+ * int got = read(fd, buf, 1024);
+ * if (got < 0) {
+ * virStreamAbort(st);
+ * break;
+ * }
+ * if (got == 0) {
+ * virStreamFinish(st);
+ * break;
+ * }
+ * int offset = 0;
+ * while (offset < got) {
+ * int sent = virStreamSend(st, buf+offset, got-offset)
+ * if (sent < 0) {
+ * virStreamAbort(st);
+ * goto done;
+ * }
+ * offset += sent;
+ * }
+ * }
+ * if (virStreamFinish(st) < 0)
+ * ... report an error ....
+ * done:
+ * virStreamFree(st);
+ * close(fd);
+ *
+ * Returns the number of bytes written, which may be less
+ * than requested.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if the outgoing transmit buffers are full &
+ * the stream is marked as non-blocking.
+ */
+int virStreamSend(virStreamPtr stream,
+ const char *data,
+ size_t nbytes)
+{
+ DEBUG("stream=%p, data=%p, nbytes=%zi", stream, data, nbytes);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamSend) {
+ int ret;
+ ret = (stream->driver->streamSend)(stream, data, nbytes);
+ if (ret == -2)
+ return -2;
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+
+/**
+ * virStreamRecv:
+ * @stream: pointer to the stream object
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Write a series of bytes to the stream. This method may
+ * block the calling application for an arbitrary amount
+ * of time.
+ *
+ * Errors are not guaranteed to be reported synchronously
+ * with the call, but may instead be delayed until a
+ * subsequent call.
+ *
+ * A example using this with a hypothetical file download
+ * API looks like
+ *
+ * virStreamPtr st = virStreamNew(conn, 0);
+ * int fd = open("demo.iso", O_WRONLY, 0600)
+ *
+ * virConnectDownloadFile(conn, "demo.iso", st);
+ *
+ * while (1) {
+ * char buf[1024];
+ * int got = virStreamRecv(st, buf, 1024);
+ * if (got < 0)
+ * break;
+ * if (got == 0) {
+ * virStreamFinish(st);
+ * break;
+ * }
+ * int offset = 0;
+ * while (offset < got) {
+ * int sent = write(fd, buf+offset, got-offset)
+ * if (sent < 0) {
+ * virStreamAbort(st);
+ * goto done;
+ * }
+ * offset += sent;
+ * }
+ * }
+ * if (virStreamFinish(st) < 0)
+ * ... report an error ....
+ * done:
+ * virStreamFree(st);
+ * close(fd);
+ *
+ *
+ * Returns the number of bytes read, which may be less
+ * than requested.
+ *
+ * Returns 0 when the end of the stream is reached, at
+ * which time the caller should invoke virStreamFinish()
+ * to get confirmation of stream completion.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if there is no data pending to be read & the
+ * stream is marked as non-blocking.
+ */
+int virStreamRecv(virStreamPtr stream,
+ char *data,
+ size_t nbytes)
+{
+ DEBUG("stream=%p, data=%p, nbytes=%zi", stream, data, nbytes);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamRecv) {
+ int ret;
+ ret = (stream->driver->streamRecv)(stream, data, nbytes);
+ if (ret == -2)
+ return -2;
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+
+/**
+ * virStreamSendAll:
+ * @stream: pointer to the stream object
+ * @handler: source callback for reading data from application
+ * @opaque: application defined data
+ *
+ * Send the entire data stream, reading the data from the
+ * requested data source. This is simply a convenient alternative
+ * to virStreamSend, for apps that do blocking-I/o.
+ *
+ * A example using this with a hypothetical file upload
+ * API looks like
+ *
+ * int mysource(virStreamPtr st, char *buf, int nbytes, void *opaque) {
+ * int *fd = opaque;
+ *
+ * return read(*fd, buf, nbytes);
+ * }
+ *
+ * virStreamPtr st = virStreamNew(conn, 0);
+ * int fd = open("demo.iso", O_RDONLY)
+ *
+ * virConnectUploadFile(conn, st);
+ * if (virStreamSendAll(st, mysource, &fd) < 0) {
+ * ...report an error ...
+ * goto done;
+ * }
+ * if (virStreamFinish(st) < 0)
+ * ...report an error...
+ * virStreamFree(st);
+ * close(fd);
+ *
+ * Returns 0 if all the data was succesfully sent. The caller
+ * should invoke virStreamFinish(st) to flush the stream upon
+ * success and then virStreamFree
+ *
+ * Returns -1 upon any error, with virStreamAbort() already
+ * having been called, so the caller need only call
+ * virStreamFree()
+ */
+int virStreamSendAll(virStreamPtr stream,
+ virStreamSourceFunc handler,
+ void *opaque)
+{
+ char *bytes = NULL;
+ int want = 1024*64;
+ int ret = -1;
+ DEBUG("stream=%p, handler=%p, opaque=%p", stream, handler, opaque);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->flags & VIR_STREAM_NONBLOCK) {
+ virLibConnError(NULL, VIR_ERR_OPERATION_INVALID,
+ _("data sources cannot be used for non-blocking streams"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(bytes, want) < 0) {
+ virReportOOMError(stream->conn);
+ goto cleanup;
+ }
+
+ for (;;) {
+ int got, offset = 0;
+ got = (handler)(stream, bytes, want, opaque);
+ if (got < 0) {
+ virStreamAbort(stream);
+ goto cleanup;
+ }
+ if (got == 0)
+ break;
+ while (offset < got) {
+ int done;
+ done = virStreamSend(stream, bytes + offset, got - offset);
+ if (done < 0)
+ goto cleanup;
+ offset += done;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ VIR_FREE(bytes);
+
+ /* Copy to connection error object for back compatability */
+ if (ret != 0)
+ virSetConnError(stream->conn);
+
+ return ret;
+}
+
+
+/**
+ * virStreamRecvAll:
+ * @stream: pointer to the stream object
+ * @handler: sink callback for writing data to application
+ * @opaque: application defined data
+ *
+ * Receive the entire data stream, sending the data to the
+ * requested data sink. This is simply a convenient alternative
+ * to virStreamRecv, for apps that do blocking-I/o.
+ *
+ * A example using this with a hypothetical file download
+ * API looks like
+ *
+ * int mysink(virStreamPtr st, const char *buf, int nbytes, void *opaque) {
+ * int *fd = opaque;
+ *
+ * return write(*fd, buf, nbytes);
+ * }
+ *
+ * virStreamPtr st = virStreamNew(conn, 0);
+ * int fd = open("demo.iso", O_WRONLY)
+ *
+ * virConnectUploadFile(conn, st);
+ * if (virStreamRecvAll(st, mysink, &fd) < 0) {
+ * ...report an error ...
+ * goto done;
+ * }
+ * if (virStreamFinish(st) < 0)
+ * ...report an error...
+ * virStreamFree(st);
+ * close(fd);
+ *
+ * Returns 0 if all the data was succesfully received. The caller
+ * should invoke virStreamFinish(st) to flush the stream upon
+ * success and then virStreamFree
+ *
+ * Returns -1 upon any error, with virStreamAbort() already
+ * having been called, so the caller need only call
+ * virStreamFree()
+ */
+int virStreamRecvAll(virStreamPtr stream,
+ virStreamSinkFunc handler,
+ void *opaque)
+{
+ char *bytes = NULL;
+ int want = 1024*64;
+ int ret = -1;
+ DEBUG("stream=%p, handler=%p, opaque=%p", stream, handler, opaque);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->flags & VIR_STREAM_NONBLOCK) {
+ virLibConnError(NULL, VIR_ERR_OPERATION_INVALID,
+ _("data sinks cannot be used for non-blocking streams"));
+ goto cleanup;
+ }
+
+
+ if (VIR_ALLOC_N(bytes, want) < 0) {
+ virReportOOMError(stream->conn);
+ goto cleanup;
+ }
+
+ for (;;) {
+ int got, offset = 0;
+ got = virStreamRecv(stream, bytes, want);
+ if (got < 0)
+ goto cleanup;
+ if (got == 0)
+ break;
+ while (offset < got) {
+ int done;
+ done = (handler)(stream, bytes + offset, got - offset, opaque);
+ if (done < 0) {
+ virStreamAbort(stream);
+ goto cleanup;
+ }
+ offset += done;
+ }
+ }
+ ret = 0;
+
+cleanup:
+ VIR_FREE(bytes);
+
+ /* Copy to connection error object for back compatability */
+ if (ret != 0)
+ virSetConnError(stream->conn);
+
+ return ret;
+}
+
+
+/**
+ * virStreamEventAddCallback
+ * @stream: pointer to the stream object
+ * @events: set of events to monitor
+ * @cb: callback to invoke when an event occurs
+ * @opaque: application defined data
+ * @ff: callback to free @opaque data
+ *
+ * Register a callback to be notified when a stream
+ * becomes writable, or readable. This is most commonly
+ * used in conjunction with non-blocking data streams
+ * to integrate into an event loop
+ *
+ * Returns 0 on success, -1 upon error
+ */
+int virStreamEventAddCallback(virStreamPtr stream,
+ int events,
+ virStreamEventCallback cb,
+ void *opaque,
+ virFreeCallback ff)
+{
+ DEBUG("stream=%p, events=%d, cb=%p, opaque=%p, ff=%p", stream, events, cb, opaque, ff);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamAddCallback) {
+ int ret;
+ ret = (stream->driver->streamAddCallback)(stream, events, cb, opaque, ff);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+
+/**
+ * virStreamEventUpdateCallback
+ * @stream: pointer to the stream object
+ * @events: set of events to monitor
+ *
+ * Changes the set of events to monitor for a stream. This allows
+ * for event notification to be changed without having to
+ * unregister & register the callback completely. This method
+ * is guarenteed to succeed if a callback is already registered
+ *
+ * Returns 0 on success, -1 if no callback is registered
+ */
+int virStreamEventUpdateCallback(virStreamPtr stream,
+ int events)
+{
+ DEBUG("stream=%p, events=%d", stream, events);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamUpdateCallback) {
+ int ret;
+ ret = (stream->driver->streamUpdateCallback)(stream, events);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+/**
+ * virStreamEventRemoveCallback
+ * @stream: pointer to the stream object
+ *
+ * Remove a event callback from the stream
+ *
+ * Returns 0 on success, -1 on error
+ */
+int virStreamEventRemoveCallback(virStreamPtr stream)
+{
+ DEBUG("stream=%p", stream);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamRemoveCallback) {
+ int ret;
+ ret = (stream->driver->streamRemoveCallback)(stream);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+/**
+ * virStreamFinish:
+ * @stream: pointer to the stream object
+ *
+ * Indicate that there is no further data is to be transmitted
+ * on the stream. For output streams this should be called once
+ * all data has been written. For input streams this should be
+ * called once virStreamRecv returns end-of-file.
+ *
+ * This method is a synchronization point for all asynchronous
+ * errors, so if this returns a success code the application can
+ * be sure that all data has been successfully processed.
+ *
+ * Returns 0 on success, -1 upon error
+ */
+int virStreamFinish(virStreamPtr stream)
+{
+ DEBUG("stream=%p", stream);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamFinish) {
+ int ret;
+ ret = (stream->driver->streamFinish)(stream);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+/**
+ * virStreamAbort:
+ * @stream: pointer to the stream object
+ *
+ * Request that the in progress data transfer be cancelled
+ * abnormally before the end of the stream has been reached.
+ * For output streams this can be used to inform the driver
+ * that the stream is being terminated early. For input
+ * streams this can be used to inform the driver that it
+ * should stop sending data.
+ *
+ * Returns 0 on success, -1 upon error
+ */
+int virStreamAbort(virStreamPtr stream)
+{
+ DEBUG("stream=%p", stream);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ if (stream->driver &&
+ stream->driver->streamAbort) {
+ int ret;
+ ret = (stream->driver->streamAbort)(stream);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError (stream->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ /* Copy to connection error object for back compatability */
+ virSetConnError(stream->conn);
+ return -1;
+}
+
+/**
+ * virStreamFree:
+ * @stream: pointer to the stream object
+ *
+ * Decrement the reference count on a stream, releasing
+ * the stream object if the reference count has hit zero.
+ *
+ * There must not be a active data transfer in progress
+ * when releasing the stream. If a stream needs to be
+ * disposed of prior to end of stream being reached, then
+ * the virStreamAbort function should be called first.
+ *
+ * Returns 0 upon success, or -1 on error
+ */
+int virStreamFree(virStreamPtr stream)
+{
+ DEBUG("stream=%p", stream);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_STREAM(stream)) {
+ virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+ return (-1);
+ }
+
+ /* XXX Enforce shutdown before free'ing resources ? */
+
+ if (virUnrefStream(stream) < 0)
+ return (-1);
+ return (0);
+}
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index f8598c7649..ad579d920a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -78,6 +78,8 @@ virGetNodeDevice;
virUnrefDomain;
virUnrefConnect;
virUnrefSecret;
+virGetStream;
+virUnrefStream;
# domain_conf.h
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index cff50d5d17..7226e88a0d 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -312,4 +312,20 @@ LIBVIRT_0.7.1 {
virSecretFree;
} LIBVIRT_0.7.0;
+LIBVIRT_0.7.2 {
+ global:
+ virStreamNew;
+ virStreamRef;
+ virStreamSend;
+ virStreamRecv;
+ virStreamSendAll;
+ virStreamRecvAll;
+ virStreamEventAddCallback;
+ virStreamEventUpdateCallback;
+ virStreamEventRemoveCallback;
+ virStreamFinish;
+ virStreamAbort;
+ virStreamFree;
+} LIBVIRT_0.7.1;
+
# .... define new API here using predicted next version number ....