blob: 0db1f71f62fccc70e218fe6031fc378be5705205 [file] [log] [blame]
/* dimeclient.cpp
Example streaming DIME client for DIME server (dimeserver.cpp).
Supports three methods:
putData stores multiple data sets on the server and returns
named references to each data set
getData retrieves data sets given named references.
getImage is an example file-based image retrieval method
Change the endpoint in dime.h to your needs.
Copyright (C) 2000-2003 Robert A. van Engelen, Genivia, Inc.
All Rights Reserved.
Usage (server):
Start dimeserver on your host at port 8085 (see dimeserver.cpp):
dimeserver 8085 &
Usage (client):
dimeclient [-p] [-g] [-i] name ...
dimeclient
Without args retrieves image.jpg
dimeclient name
Retrieves image stored under name
dimeclient -p name1 name2 ...
Stores files name1, name2, etc. The storage keys are printed.
The keys provide access to the data on the server.
dimeclient -g name1 name2 ...
Retrieves files stored under keys name1, name2, etc.
The keys must correspond to the keys returned when storing
files. Files are stored locally under the key name.
Unix/Linux: add a sigpipe handler to avoid broken pipes.
*/
#include "soapH.h"
#include "dime.nsmap"
#include <assert.h>
// use the default endpoint set in dime.h for demo:
const char *endpoint = NULL;
// use the localhost for -p and -g (put and get):
const char *localhost = "http://localhost:8085";
////////////////////////////////////////////////////////////////////////////////
//
// Forward decls
//
////////////////////////////////////////////////////////////////////////////////
static void putData(struct soap*, int, char**);
static void getData(struct soap*, int, char**);
static void getImage(struct soap*, char*);
static void saveData(ns__Data&, const char*);
////////////////////////////////////////////////////////////////////////////////
//
// Streaming DIME attachment content handlers
//
////////////////////////////////////////////////////////////////////////////////
static void *dime_read_open(struct soap*, void*, const char*, const char*, const char*);
static void dime_read_close(struct soap*, void*);
static size_t dime_read(struct soap*, void*, char*, size_t);
static void *dime_write_open(struct soap*, const char*, const char*, const char*);
static void dime_write_close(struct soap*, void*);
static int dime_write(struct soap*, void*, const char*, size_t);
////////////////////////////////////////////////////////////////////////////////
//
// Main
//
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char **argv)
{ struct soap soap;
// use HTTP 1.1 chunking
// HTTP chunking allows streaming of DIME content without requiring DIME attachment size to be set
// DIME attachments can be streamed without chunking ONLY if the attachment size is set
soap_init1(&soap, SOAP_IO_CHUNK);
// set DIME callbacks
soap.fdimereadopen = dime_read_open;
soap.fdimereadclose = dime_read_close;
soap.fdimeread = dime_read;
soap.fdimewriteopen = dime_write_open;
soap.fdimewriteclose = dime_write_close;
soap.fdimewrite = dime_write;
// connect timeout value (not supported by Linux)
soap.connect_timeout = 10;
// IO timeouts
soap.send_timeout = 30;
soap.recv_timeout = 30;
// Unix/Linux SIGPIPE, this is OS dependent:
// soap.accept_flags = SO_NOSIGPIPE; // some systems like this
// soap.socket_flags = MSG_NOSIGNAL; // others need this
// signal(SIGPIPE, sigpipe_handle); // or a sigpipe handler (portable)
if (argc < 3)
{ char *name;
if (argc < 2)
name = "image.jpg";
else
name = argv[1];
getImage(&soap, name);
}
else
{ switch (argv[1][1])
{ case 'p':
endpoint = localhost;
putData(&soap, argc, argv);
break;
case 'g':
endpoint = localhost;
getData(&soap, argc, argv);
break;
default:
fprintf(stderr, "Usage: [-p] [-g] name ...\n");
exit(0);
}
}
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);
return SOAP_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// Helper functions
//
////////////////////////////////////////////////////////////////////////////////
static void putData(struct soap *soap, int argc, char **argv)
{ arrayOfData data;
arrayOfName names;
data.resize(argc - 2);
for (int i = 2; i < argc; i++)
{ data[i - 2].__ptr = (unsigned char*)argv[i];
// MUST set id or type to enable DIME
// zero size indicates streaming DIME (this requires HTTP chunking)
data[i - 2].type = "";
}
if (soap_call_ns__putData(soap, endpoint, NULL, &data, &names))
soap_print_fault(soap, stderr);
else
{ printf("Data stored with keys:\n");
for (int j = 0; j < names.size(); j++)
printf("\t%s\n", names[j]);
printf("Use these keys to retrieve the data\n");
}
}
static void getData(struct soap *soap, int argc, char **argv)
{ arrayOfData data;
arrayOfName names;
names.resize(argc - 2);
for (int i = 2; i < argc; i++)
names[i - 2] = argv[i];
soap->user = (void*)names.__ptr;
if (soap_call_ns__getData(soap, endpoint, NULL, &names, &data))
soap_print_fault(soap, stderr);
else
{ for (int j = 0; j < data.size(); j++)
if (!data[j].id)
saveData(data[j], argv[j + 2]);
printf("Data retrieved\n");
}
}
static void getImage(struct soap *soap, char *name)
{ ns__Data image;
arrayOfName temp;
temp.resize(1);
temp[0] = name;
soap->user = (void*)temp.__ptr;
if (soap_call_ns__getImage(soap, endpoint, NULL, name, image))
soap_print_fault(soap, stderr);
else if (image.id)
{ if (image.__size)
printf("Got image %s size=%d type=%s through streaming DIME\n", name, image.__size, image.type?image.type:"");
else
printf("Got image %s type=%s through chunked streaming DIME\n", name, image.type?image.type:"");
}
else
{ printf("Got image %s\n", name);
saveData(image, name);
}
}
static void saveData(ns__Data& data, const char *name)
{ char *buf = (char*)data.__ptr;
int len = data.__size;
FILE *fd = fopen(name, "wb");
if (!fd)
{ fprintf(stderr, "Cannot save file %s\n", name);
return;
}
while (len)
{ size_t nwritten = fwrite(buf, 1, len, fd);
if (!nwritten)
{ fprintf(stderr, "Cannot write to %s\n", name);
return;
}
len -= nwritten;
buf += nwritten;
}
printf("Saved file %s\n", name);
}
////////////////////////////////////////////////////////////////////////////////
//
// Streaming DIME attachment content handlers
//
////////////////////////////////////////////////////////////////////////////////
static void *dime_read_open(struct soap *soap, void *handle, const char *id, const char *type, const char *options)
{ FILE *fd;
// we should return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment. The handle contains the non-NULL __ptr field value which should have been set in the application.
// return value of this function will be passed on to the fdimeread and fdimereadclose callbacks. The return value will not affect the __ptr field.
fd = fopen((char*)handle, "rb");
return (void*)fd;
}
static void dime_read_close(struct soap *soap, void *handle)
{ fclose((FILE*)handle);
}
static size_t dime_read(struct soap *soap, void *handle, char *buf, size_t len)
{ return fread(buf, 1, len, (FILE*)handle);
}
static void *dime_write_open(struct soap *soap, const char *id, const char *type, const char *options)
{ // we can return NULL without setting soap->error if we don't want to use the streaming callback for this DIME attachment
FILE *handle = NULL;
char *name;
// get file name from options (not '\0' terminated)
if (options)
{ size_t len = ((unsigned char)options[2] << 8) | ((unsigned char)options[3]); // option string length
name = (char*)soap_malloc(soap, len + 1);
strncpy(name, options + 4, len);
name[len] = '\0';
handle = fopen(name, "wb");
if (!handle)
{ soap->error = SOAP_EOF; // could not open file for writing
soap->errnum = errno; // get reason
return NULL;
}
}
else
soap->error = soap_receiver_fault(soap, "Cannot save to file, because no file name was present in attachment", NULL);
return (void*)handle;
}
static void dime_write_close(struct soap *soap, void *handle)
{ fclose((FILE*)handle);
}
static int dime_write(struct soap *soap, void *handle, const char *buf, size_t len)
{ while (len)
{ size_t nwritten = fwrite(buf, 1, len, (FILE*)handle);
if (!nwritten)
{ soap->errnum = errno; // get reason
return SOAP_EOF;
}
len -= nwritten;
buf += nwritten;
}
return SOAP_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// ns__Data class
//
////////////////////////////////////////////////////////////////////////////////
ns__Data::ns__Data()
{ __ptr = NULL;
__size = 0;
id = NULL;
type = NULL;
options = NULL;
soap = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// arrayOfData class
//
////////////////////////////////////////////////////////////////////////////////
arrayOfData::arrayOfData()
{ __ptr = NULL;
__size = 0;
soap = NULL;
}
arrayOfData::arrayOfData(struct soap *soap, int n)
{ __ptr = NULL;
__size = 0;
this->soap = soap;
resize(n);
}
arrayOfData::~arrayOfData()
{ resize(0);
}
int arrayOfData::size()
{ return __size;
}
void arrayOfData::resize(int n)
{ if (__ptr)
{ if (soap) // if created by soap environment
soap_delete(soap, __ptr); // then delete
else
delete[] __ptr;
}
__size = n;
if (n <= 0)
__ptr = NULL;
else if (soap)
__ptr = soap_new_ns__Data(soap, n);
else
__ptr = new ns__Data[n];
}
ns__Data& arrayOfData::operator[](int i) const
{ assert(__ptr && i >= 0 && i < __size);
return __ptr[i];
}
////////////////////////////////////////////////////////////////////////////////
//
// arrayOfName class
//
////////////////////////////////////////////////////////////////////////////////
arrayOfName::arrayOfName()
{ __ptr = NULL;
__size = 0;
soap = NULL;
}
arrayOfName::arrayOfName(struct soap *soap, int n)
{ __ptr = NULL;
__size = 0;
this->soap = soap;
resize(n);
}
arrayOfName::~arrayOfName()
{ resize(0);
}
int arrayOfName::size()
{ return __size;
}
void arrayOfName::resize(int n)
{ if (__ptr)
{ if (soap) // if created by soap environment
soap_delete(soap, __ptr); // then delete
else
free(__ptr);
}
__size = n;
if (n <= 0)
__ptr = NULL;
else
{ if (soap)
__ptr = (char**)soap_malloc(soap, sizeof(char*) * n);
else
__ptr = (char**)malloc(sizeof(char*) * n);
memset(__ptr, 0, n);
}
}
char*& arrayOfName::operator[](int i) const
{ assert(__ptr && i >= 0 && i < __size);
return __ptr[i];
}