Streaming DIME is achieved with callback functions to fetch and store data during transmission. Three function callbacks for streaming DIME output and three callbacks for streaming DIME input are available.
Callback (function pointer)
void *(*soap.fdimereadopen)(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
Called by the gSOAP run-time DIME attachment sender to start reading from a (binary) data source for outbound transmission. The content will be read from the application’s data source in chunks using the fdimeread callback and streamed into the SOAP/XML/DIME output stream. The handle contains the value of the ptr field of an attachment struct/class, which could be a pointer to specific information such as a file descriptor or a pointer to a string to be passed to this callback. Both ptr and size fields should have been set by the application prior to the serialization of the content. The id, type, and options arguments are the DIME id, type, and options, respectively. The callback should return handle, or another pointer value which will be passed as a handle to fdimeread and fdimereadclose. The callback should return NULL and set soap->error when an error occurred. The callback should return NULL (and not set soap->error) when this particular DIME attachment is not to be streamed.
size t (*soap.fdimeread)(struct soap *soap, void *handle, char *buf, size t len)
Called by the gSOAP run-time DIME attachment sender to read more data from a (binary) data source for streaming into the output stream. The handle contains the value returned by the fdimeread- open callback. The buf argument is the buffer of length len into which a chunk of data should be stored. The actual amount of data stored in the buffer may be less than len and this amount should be returned by the application. A return value of 0 indicates an error (the callback may set soap->errnum to errno). The size field of the attachment struct/class should have been set by the application prior to the serialization of the content. The value of size indicates the total size of the content to be transmitted. When the size is zero then DIME chunked transfers can be used under certain circumstances to stream content without prior determination of attachment size, see Section 15.5 below.
void(*soap.fdimereadclose)(struct soap *soap, void *handle)
Called by the gSOAP run-time DIME attachment sender at the end of the streaming process to close the data source. The handle contains the value returned by the fdimereadopen callback. The fdimewriteclose callback is called after successfully transmitting the data or when an error occurred. void *(*soap.fdimewriteopen)(struct soap *soap, const char *id, const char *type, const char *op- tions)
Called by the gSOAP run-time DIME attachment receiver to start writing an inbound DIME at- tachment to an application’s data store. The content is streamed into an application data store through multiple fdimewrite calls from the gSOAP attachment receiver. The id, type, and options arguments are the DIME id, type, and options respectively. The callback should return a handle which is passed to the fdimewrite and fdimewriteclose callbacks. The ptr field of the attachment struct/class is set to the value of this handle. The size field is set to the total size of the attachment after receiving the entire content. The size is unknown in advance because DIME attachments may be chunked.
int (*soap.fdimewrite)(struct soap *soap, void *handle, const char *buf, size t len)
Called by the gSOAP run-time DIME attachment receiver to write part of an inbound DIME attach- ment to an application’s data store. The handle contains the value returned by the fdimewriteopen callback. The buf argument contains the data of length len. The callback should return a gSOAP error code (e.g. SOAP OK when no error occurred).
void(*soap.fdimewriteclose)(struct soap *soap, void *handle)
Called by the gSOAP run-time DIME attachment receiver at the end of the streaming process to close the data store. The fdimewriteclose callback is called after successfully receiving the data or when an error occurred. The handle contains the value returned by the fdimewriteopen callback.
In addition, a void*userfield in thestruct soapdata structure is available to pass user-defined data to the callbacks. This way, you can set soap.user to point to application data that the callbacks need such as a file name for example.
The following example illustrates the client-side initialization of an image attachment struct to stream a file into a DIME attachment:
int main() {
struct soap soap;
struct xsd base64Binary image; FILE *fd;
struct stat sb; soap init(&soap);
if (!fstat(fileno(fd), &sb) && sb.st size > 0)
{ // because we can get the length of the file, we can stream it soap.fdimereadopen = dime read open;
soap.fdimereadclose = dime read close; soap.fdimeread = dime read;
image. ptr = (unsigned char*)fd; // must set to non-NULL (this is our fd handle which we need in the callbacks)
image. size = sb.st size; // must set size }
else
{ // don’t know the size, so buffer it size t i;
int c;
image. ptr = (unsigned char*)soap malloc(&soap, MAX FILE SIZE); for (i = 0; i < MAX FILE SIZE; i++)
{ if ((c = fgetc(fd)) == EOF) break; image. ptr[i] = c; } fclose(fd); image. size = i; } image.type = ”image/jpeg”;
image.options = soap dime option(&soap, 0, ”My picture”); soap call ns method(&soap, ...);
... }
void *dime read open(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
{ return handle; }
void dime read close(struct soap *soap, void *handle) { fclose((FILE*)handle);
}
size t dime read(struct soap *soap, void *handle, char *buf, size t len) { return fread(buf, 1, len, (FILE*)handle);
}
The following example illustrates the streaming of a DIME attachment into a file by a client:
int main()
soap init(&soap);
soap.fdimewriteopen = dime write open; soap.fdimewriteclose = dime write close; soap.fdimewrite = dime write;
soap call ns method(&soap, ...); ...
}
void *dime write open(struct soap *soap, const char *id, const char *type, const char *options) {
FILE *handle = fopen(”somefile”, ”wb”); if (!handle)
{
soap->error = SOAP EOF;
soap->errnum = errno; // get reason }
return (void*)handle; }
void dime write close(struct soap *soap, void *handle) { fclose((FILE*)handle);
}
int dime write(struct soap *soap, void *handle, const char *buf, size t len) {
size t nwritten; while (len) {
nwritten = fwrite(buf, 1, len, (FILE*)handle); if (!nwritten)
{
soap->errnum = errno; // get reason return SOAP EOF;
}
len -= nwritten; buf += nwritten; }
return SOAP OK; }
Note that compression can be used with DIME to compress the entire message. However, com- pression requires buffering to determine the HTTP content length header, which cancels the benefits of streaming DIME. To avoid this, you should use chunked HTTP (with the output- mode SOAP IO CHUNK flag) with compression and streaming DIME. At the server side, when you set SOAP IO CHUNK before calling soap serve, gSOAP will automatically revert to buffering (SOAP IO STOREflag is set). You can check this flag with(soap-¿omode & SOAP IO) == SOAP IO CHUNK
to see if the client accepts chunking. More information about streaming chunked DIME can be found in Section 15.5.
Caution: Theoptionsfield is a DIME-specific data structure, consisting of a 4 byte header containing the option type info (hi byte, lo byte), option string length (hi byte, lo byte), followed by a non-’\0’ terminated string. The gSOAP DIME handler recognizes one option at most.