diff options
Diffstat (limited to 'samples/dime/dimeclient.cpp')
-rw-r--r-- | samples/dime/dimeclient.cpp | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/samples/dime/dimeclient.cpp b/samples/dime/dimeclient.cpp new file mode 100644 index 0000000..0db1f71 --- /dev/null +++ b/samples/dime/dimeclient.cpp @@ -0,0 +1,388 @@ +/* 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]; +} + |